/* link script support */ /* label opcode operand */ #include #include #include #include #include #include "script.h" /*!re2c re2c:define:YYCTYPE = char; re2c:yyfill:enable = 0; // :-~ includes ; which interferes with comments. ident = [:<-~][0-~]*; ws = [ \t]; eof = "\x00"; number_prefix = [%$0-9]; ident_prefix = [:-~]; string_prefix = ['"]; */ namespace { std::unordered_map opcodes = { #define x(op) { #op, OP_##op }, #include "ops.h" #undef x /* aliases */ { "AUX", OP_ADR }, { "REZ", OP_RES }, { "LIN", OP_LNK }, { "KIN", OP_KND }, { "=", OP_EQ } }; } static int x_number_operand(const char *YYCURSOR) { const char *iter = YYCURSOR; // const char *YYMARKER = nullptr; uint32_t rv = 0; /*!re2c * { throw std::invalid_argument("bad operand"); } '%' [01]+ { ++iter; for(;iter < YYCURSOR; ++iter) { rv <<= 1; rv |= *iter - '0'; } goto exit; } '$' [A-Fa-f0-9]+ { ++iter; for(;iter < YYCURSOR; ++iter) { char c = *iter | 0x20; rv <<= 4; if (c <= '9') rv |= c - '0'; else rv |= c - 'a' + 10; } goto exit; } [0-9]+ { for(;iter < YYCURSOR; ++iter) { rv *= 10; rv += *iter - '0'; } goto exit; } */ exit: char c = *YYCURSOR; if (isspace(c) || c == 0) return rv; throw std::invalid_argument("bad operand"); } static std::string x_label_operand(const char *YYCURSOR, bool insensitive) { const char *iter = YYCURSOR; // const char *YYMARKER = nullptr; std::string rv; /*!re2c * { throw std::invalid_argument("bad operand"); } ident { rv = std::string(iter, YYCURSOR); if (insensitive) for (char &c : rv) rv = std::toupper(c); goto exit; } */ exit: char c = *YYCURSOR; if (isspace(c) || c == 0) { //look up symbol, verify it's an absolute value, etc return rv; } throw std::invalid_argument("bad operand"); } static std::string x_string_operand(const char *YYCURSOR) { const char *iter = YYCURSOR; std::string rv; /*!re2c * { throw std::invalid_argument("bad operand"); } ['] [^']* ['] | ["] [^"]* ["] { rv = std::string(iter+1, YYCURSOR-1); goto exit; } */ exit: char c = *YYCURSOR; if (isspace(c) || c == 0) return rv; throw std::invalid_argument("bad operand"); } uint32_t number_operand(const char *YYCURSOR, const std::unordered_map &map, int flags) { const char *cp = YYCURSOR; // const char *YYMARKER = nullptr; /*!re2c * { throw std::invalid_argument("bad operand"); } [;] | eof { if (flags & OP_REQUIRED) throw std::invalid_argument("missing operand"); return 0; } number_prefix { return x_number_operand(cp); } ident_prefix { std::string s = x_label_operand(cp, flags & OP_INSENSITIVE); auto iter = map.find(s); if (iter == map.end()) throw std::runtime_error("Bad symbol"); return iter->second; } */ } int ovr_operand(const char *YYCURSOR) { int rv = 0; const char *YYMARKER = nullptr; /*!re2c * { throw std::invalid_argument("bad operand"); } [;] | eof { return OVR_NONE; } 'ALL' { rv = OVR_ALL; } 'OFF' { rv = OVR_OFF; } */ char c = *YYCURSOR; if (isspace(c) || c == 0) return rv; throw std::invalid_argument("bad operand"); } std::string label_operand(const char *YYCURSOR, int flags) { const char *cp = YYCURSOR; // const char *YYMARKER = nullptr; /*!re2c * { throw std::invalid_argument("bad operand"); } [;] | eof { if (flags & OP_REQUIRED) throw std::invalid_argument("missing operand"); return std::string(); } ident_prefix { return x_label_operand(cp, flags & OP_INSENSITIVE); } */ } std::string path_operand(const char *YYCURSOR, int flags) { std::string rv; const char *iter = YYCURSOR; // const char *YYMARKER = nullptr; /*!re2c * { throw std::invalid_argument("bad operand"); } [;] | eof { if (flags & OP_REQUIRED) throw std::invalid_argument("missing operand"); return rv; } string_prefix { return x_string_operand(iter); } // don't allow leading quotes, eof, or comment chars [^ \t\x00;*'"][^ \t\x00]* { rv = std::string(iter, YYCURSOR); goto exit; } */ exit: char c = *YYCURSOR; if (isspace(c) || c == 0) return rv; throw std::invalid_argument("bad operand"); } std::string string_operand(const char *YYCURSOR, int flags) { const char *cp = YYCURSOR; // const char *YYMARKER = nullptr; /*!re2c * { throw std::invalid_argument("bad operand"); } [;] | eof { if (flags & OP_REQUIRED) throw std::invalid_argument("missing operand"); return std::string(); } string_prefix { return x_string_operand(cp); } */ } void no_operand(const char *YYCURSOR) { /*!re2c * { throw std::invalid_argument("bad operand"); } [;] | eof { return; } */ } void parse_line(const char *YYCURSOR) { label_t label; opcode_t opcode = OP_NONE; const char *iter = YYCURSOR; const char *YYMARKER = nullptr; /*!re2c * { throw std::invalid_argument("bad label"); } [;*] | eof { return; } ws { goto opcode; } ident / (ws|eof) { label = std::string(iter, YYCURSOR); goto opcode; } */ opcode: while (isspace(*YYCURSOR)) ++YYCURSOR; iter = YYCURSOR; /*!re2c * { throw std::invalid_argument("bad opcode"); } [;]|eof { return; } '=' / (ws|eof) { opcode = OP_EQ; goto operand; } [A-Za-z]+ / (ws|eof) { size_t l = YYCURSOR - iter; if (l > 3) l = 3; std::string s(iter, iter + l); for (char &c : s) c = std::toupper(c); auto iter = opcodes.find(s); if (iter == opcodes.end()) { throw std::invalid_argument("bad opcode"); } opcode = iter->second; goto operand; } */ operand: while (isspace(*YYCURSOR)) ++YYCURSOR; iter = YYCURSOR; void evaluate(label_t label, opcode_t opcode, const char *); evaluate(label, opcode, YYCURSOR); }