diff --git a/link.cpp b/link.cpp index 2e5601a..7884715 100644 --- a/link.cpp +++ b/link.cpp @@ -63,6 +63,44 @@ namespace { std::vector segments; std::vector> relocations; + std::unordered_map file_types = { + + { "NON", 0x00 }, + { "BAD", 0x01 }, + { "BIN", 0x06 }, + { "TXT", 0x04 }, + { "DIR", 0x0f }, + { "ADB", 0x19 }, + { "AWP", 0x1a }, + { "ASP", 0x1b }, + { "GSB", 0xab }, + { "TDF", 0xac }, + { "BDF", 0xad }, + { "SRC", 0xb0 }, + { "OBJ", 0xb1 }, + { "LIB", 0xb2 }, + { "S16", 0xb3 }, + { "RTL", 0xb4 }, + { "EXE", 0xb5 }, + { "PIF", 0xb6 }, + { "TIF", 0xb7 }, + { "NDA", 0xb8 }, + { "CDA", 0xb9 }, + { "TOL", 0xba }, + { "DRV", 0xbb }, + { "DOC", 0xbf }, + { "PNT", 0xc0 }, + { "PIC", 0xc1 }, + { "FON", 0xcb }, + { "PAS", 0xef }, + { "CMD", 0xf0 }, + { "LNK", 0xf8 }, + { "BAS", 0xfc }, + { "VAR", 0xfd }, + { "REL", 0xfe }, + { "SYS", 0xff }, + + }; } @@ -120,6 +158,8 @@ namespace { unsigned kind = 0x0000; unsigned sav = 0; bool end = false; + bool fas = false; + int ovr = OVR_OFF; size_t pos_offset = 0; size_t len_offset = 0; @@ -545,16 +585,24 @@ static bool op_after_end(opcode_t op) { } } -static uint32_t eval(operand_t op) { - if (std::holds_alternative(op)) return std::get(op); - std::string &name = std::get(op); - auto iter = local_symbol_table.find(name); - if (iter == local_symbol_table.end()) throw std::runtime_error("Bad symbol"); - return iter->second; + +extern uint32_t number_operand(const char *cursor, int flags = OP_REQUIRED); +extern uint32_t number_operand(const char *cursor, const std::unordered_map &, int flags = OP_REQUIRED); +extern int ovr_operand(const char *cursor); +extern std::string label_operand(const char *cursor, int flags = OP_REQUIRED); +extern std::string string_operand(const char *cursor, int flags = OP_REQUIRED); +extern std::string path_operand(const char *cursor, int flags = OP_REQUIRED); + +extern void no_operand(const char *cursor); + +static std::string basename(const std::string &str) { + + auto ix = str.find_last_of("/:"); + if (ix == str.npos) return str; + return str.substr(0, ix); } - -void evaluate(label_t label, opcode_t opcode, operand_t operand) { +void evaluate(label_t label, opcode_t opcode, const char *cursor) { // todo - should move operand parsing to here. @@ -562,8 +610,11 @@ void evaluate(label_t label, opcode_t opcode, operand_t operand) { case OP_DO: if (active_bits & 0x80000000) throw std::runtime_error("too much do do"); active_bits <<= 1; - active_bits |= eval(operand) ? 1 : 0; - active = (active_bits & (active_bits + 1)) == 0; + if (active) { + uint32_t value = number_operand(cursor, local_symbol_table); + active_bits |= value ? 1 : 0; + active = (active_bits & (active_bits + 1)) == 0; + } return; break; @@ -623,22 +674,20 @@ void evaluate(label_t label, opcode_t opcode, operand_t operand) { case OP_TYP: - // todo - should evaluate with file type dictionary. - ftype = eval(operand); + ftype = number_operand(cursor, file_types, OP_REQUIRED | OP_INSENSITIVE); break; case OP_ADR: - atype = eval(operand); + atype = number_operand(cursor, local_symbol_table); break; - case OP_KND: - kind = eval(operand); + kind = number_operand(cursor, local_symbol_table); break; case OP_LKV: { /* specify linker version */ /* 0 = binary, 1 = Linker.GS, 2 = Linker.XL, 3 = convert to OMF object file */ - uint32_t value = eval(operand); + uint32_t value = number_operand(cursor, local_symbol_table); switch (value) { case 0: throw std::runtime_error("binary linker not supported"); case 3: throw std::runtime_error("object file linker not supported"); @@ -654,7 +703,7 @@ void evaluate(label_t label, opcode_t opcode, operand_t operand) { case OP_VER: { /* OMF version, 1 or 2 */ - uint32_t value = eval(operand); + uint32_t value = number_operand(cursor, local_symbol_table); if (value != 2) throw std::runtime_error("bad OMF version"); @@ -662,29 +711,40 @@ void evaluate(label_t label, opcode_t opcode, operand_t operand) { break; } - case OP_LNK: + case OP_LNK: { if (end) throw std::runtime_error("link after end"); - //link_unit(std::get(operand)); + + std::string path = path_operand(cursor); + process_unit(path); break; + } - case OP_SAV: + case OP_SAV: { if (end) throw std::runtime_error("save after end"); - if (save_file.empty()) save_file = std::get(operand); - /* if linker version 1, save to disk */ - /* if linker version 2, finish the current segment */ - if (lkv == 1) { + std::string path = path_operand(cursor); + + /* use 1st SAV as the path */ + if (save_file.empty()) save_file = path; + + /* + lkv 0 = binary linker (unsupported) + lkv 1 = 1 segment GS linker + lkv 2 = multi-segment GS linker + lkv 3 = convert REL to OMF object file (unsupported) + */ + + if (lkv == 1 || lkv == 2 || lkv == 3) { auto &seg = segments.back(); - seg.segname = std::get(operand); + std::string base = basename(path); + seg.segname = std::move(base); seg.kind = kind; + } + if (lkv == 1) { finish(); end = true; } if (lkv == 2) { - auto &seg = segments.back(); - seg.segname = std::get(operand); - seg.kind = kind; - /* add a new segment */ segments.emplace_back(); relocations.emplace_back(); @@ -692,9 +752,9 @@ void evaluate(label_t label, opcode_t opcode, operand_t operand) { } ++sav; break; + } case OP_KBD: { - std::string prompt; char buffer[256]; if (!isatty(STDIN_FILENO)) return; @@ -703,8 +763,7 @@ void evaluate(label_t label, opcode_t opcode, operand_t operand) { if (local_symbol_table.find(label) != local_symbol_table.end()) return; - if (std::holds_alternative(operand)) - prompt = std::get(operand); + std::string prompt = string_operand(cursor, OP_OPTIONAL); if (prompt.empty()) prompt = "Give value for " + label; prompt += ": "; @@ -713,12 +772,11 @@ void evaluate(label_t label, opcode_t opcode, operand_t operand) { char *cp = fgets(buffer, sizeof(buffer), stdin); - if (!cp) return; + if (!cp) throw std::runtime_error("Bad input"); - operand_t number_operand(const char *YYCURSOR, bool required); - operand_t op = number_operand(cp, true); + uint32_t value = number_operand(cp, local_symbol_table, true); - define(label, eval(op), LBL_KBD); + define(label, value, LBL_KBD); break; } @@ -726,10 +784,10 @@ void evaluate(label_t label, opcode_t opcode, operand_t operand) { // POS label << sets label = current segment offset // POS << resets pos byte counter. - if (std::holds_alternative(operand)) { + std::string label = label_operand(cursor, OP_OPTIONAL); + if (label.empty()) { pos_offset = segments.back().data.size(); } else { - std::string label = std::get(operand); uint32_t value = segments.back().data.size() - pos_offset; define(label, value, LBL_POS); @@ -739,30 +797,44 @@ void evaluate(label_t label, opcode_t opcode, operand_t operand) { case OP_LEN: { // LEN label // sets label = length of most recent file linked - std::string label = std::get(operand); + + std::string label = label_operand(cursor); uint32_t value = len_offset; define(label, value, LBL_LEN); break; } case OP_EQ: - define(label, eval(operand), LBL_EQ); + define(label, number_operand(cursor, local_symbol_table), LBL_EQ); break; case OP_EQU: - define(label, eval(operand), LBL_EQU); + define(label, number_operand(cursor, local_symbol_table), LBL_EQU); break; case OP_GEQ: - define(label, eval(operand), LBL_GEQ); + define(label, number_operand(cursor, local_symbol_table), LBL_GEQ); break; case OP_FAS: /* fast linker, only 1 file allowed */ + fas = true; + break; case OP_OVR: - case OP_PUT: - case OP_IF: + ovr = ovr_operand(cursor); break; - case OP_ASM: + case OP_PUT: { + std::string path = path_operand(cursor); + break; + } + case OP_IF: { + std::string path = path_operand(cursor); + break; + } + + case OP_ASM: { + std::string path = path_operand(cursor); + break; + } default: throw std::runtime_error("opcode not yet supported"); } diff --git a/script.h b/script.h index 0286307..2beae7e 100644 --- a/script.h +++ b/script.h @@ -3,10 +3,8 @@ #include #include -#include typedef std::string label_t; -typedef std::variant operand_t; enum opcode_t { @@ -23,4 +21,10 @@ enum { OVR_OFF = 0 }; +enum { + OP_OPTIONAL = 0, + OP_REQUIRED = 1, + OP_INSENSITIVE = 2 +}; + #endif diff --git a/script.re2c b/script.re2c index fe6cb61..41c8e47 100644 --- a/script.re2c +++ b/script.re2c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include @@ -51,45 +50,6 @@ namespace { { "=", OP_EQ } }; - - std::unordered_map types = { - - { "NON", 0x00 }, - { "BAD", 0x01 }, - { "BIN", 0x06 }, - { "TXT", 0x04 }, - { "DIR", 0x0f }, - { "ADB", 0x19 }, - { "AWP", 0x1a }, - { "ASP", 0x1b }, - { "GSB", 0xab }, - { "TDF", 0xac }, - { "BDF", 0xad }, - { "SRC", 0xb0 }, - { "OBJ", 0xb1 }, - { "LIB", 0xb2 }, - { "S16", 0xb3 }, - { "RTL", 0xb4 }, - { "EXE", 0xb5 }, - { "PIF", 0xb6 }, - { "TIF", 0xb7 }, - { "NDA", 0xb8 }, - { "CDA", 0xb9 }, - { "TOL", 0xba }, - { "DRV", 0xbb }, - { "DOC", 0xbf }, - { "PNT", 0xc0 }, - { "PIC", 0xc1 }, - { "FON", 0xcb }, - { "PAS", 0xef }, - { "CMD", 0xf0 }, - { "LNK", 0xf8 }, - { "BAS", 0xfc }, - { "VAR", 0xfd }, - { "REL", 0xfe }, - { "SYS", 0xff }, - - }; } @@ -138,7 +98,7 @@ exit: throw std::invalid_argument("bad operand"); } -static std::string x_label_operand(const char *YYCURSOR) { +static std::string x_label_operand(const char *YYCURSOR, bool insensitive) { const char *iter = YYCURSOR; // const char *YYMARKER = nullptr; std::string rv; @@ -147,6 +107,8 @@ static std::string x_label_operand(const char *YYCURSOR) { ident { rv = std::string(iter, YYCURSOR); + if (insensitive) + for (char &c : rv) rv = std::toupper(c); goto exit; } */ @@ -177,64 +139,33 @@ exit: throw std::invalid_argument("bad operand"); } +uint32_t number_operand(const char *YYCURSOR, const std::unordered_map &map, int flags) { - -/* not static - called from link.cpp */ -operand_t number_operand(const char *YYCURSOR, bool required = true) { - - const char *iter = YYCURSOR; + const char *cp = YYCURSOR; // const char *YYMARKER = nullptr; /*!re2c * { throw std::invalid_argument("bad operand"); } [;*] | eof { - if (!required) return 0; - throw std::invalid_argument("missing operand"); + if (flags & OP_REQUIRED) + throw std::invalid_argument("missing operand"); + return 0; } number_prefix { - return x_number_operand(iter); + return x_number_operand(cp); } - ident_prefix { return x_label_operand(iter); } - */ - -} - -static uint32_t type_operand(const char *YYCURSOR, bool required = true) { - - const char *iter = YYCURSOR; - const char *YYMARKER = nullptr; - uint32_t rv = 0; - /*!re2c - * { throw std::invalid_argument("bad operand"); } - - [;*] | eof { - if (!required) return rv; - throw std::invalid_argument("missing operand"); - } - number_prefix { return x_number_operand(iter); } - - [A-Za-z][A-Za-z0-9]{2} { - std::string s(iter, YYCURSOR); - for(char &c : s) c = std::toupper(c); - auto iter = types.find(s); - if (iter == types.end()) { - throw std::invalid_argument("bad operand"); - } - rv = iter->second; - goto exit; + 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; } */ -exit: - char c = *YYCURSOR; - if (isspace(c) || c == 0) return rv; - - throw std::invalid_argument("bad operand"); } - -static int ovr_operand(const char *YYCURSOR) { +int ovr_operand(const char *YYCURSOR) { int rv = 0; const char *YYMARKER = nullptr; @@ -257,49 +188,44 @@ static int ovr_operand(const char *YYCURSOR) { throw std::invalid_argument("bad operand"); } -static std::string label_operand(const char *YYCURSOR, bool required = true) { - std::string rv; - const char *iter = YYCURSOR; +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 (!required) return rv; - throw std::invalid_argument("missing operand"); + if (flags & OP_REQUIRED) + throw std::invalid_argument("missing operand"); + return std::string(); } - ident { - rv = std::string(iter, YYCURSOR); - goto exit; + ident_prefix { + return x_label_operand(cp, flags & OP_INSENSITIVE); } */ - -exit: - char c = *YYCURSOR; - if (isspace(c) || c == 0) return rv; - - throw std::invalid_argument("bad operand"); } -static std::string path_operand(const char *YYCURSOR, bool required = true) { +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 (!required) return rv; - throw std::invalid_argument("missing operand"); + 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 - [^;*\x00'"][^ \t]* { + . [^ \t]* { rv = std::string(iter, YYCURSOR); goto exit; } - ['] [^']* ['] | ["] [^"]* ["] { - rv = std::string(iter+1, YYCURSOR-1); - goto exit; - } */ @@ -310,8 +236,27 @@ exit: 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"); } -static void no_operand(const char *YYCURSOR) { + [;*] | 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; } @@ -319,35 +264,10 @@ static void no_operand(const char *YYCURSOR) { } -static std::string string_operand(const char *YYCURSOR, bool required = true) { - - std::string rv; - const char *iter = YYCURSOR; - // const char *YYMARKER = nullptr; - /*!re2c - * { throw std::invalid_argument("bad operand"); } - [;*] | eof { - if (!required) return rv; - throw std::invalid_argument("missing 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"); -} - - - void parse_line(const char *YYCURSOR) { label_t label; opcode_t opcode = OP_NONE; - operand_t operand; const char *iter = YYCURSOR; const char *YYMARKER = nullptr; @@ -398,64 +318,9 @@ operand: while (isspace(*YYCURSOR)) ++YYCURSOR; iter = YYCURSOR; + void evaluate(label_t label, opcode_t opcode, const char *); - switch(opcode) { - case OP_LNK: - case OP_PUT: - case OP_ASM: - case OP_SAV: - case OP_LIB: - case OP_IF: - case OP_PFX: - case OP_IMP: - case OP_RES: - case OP_FIL: - operand = path_operand(YYCURSOR); - break; - case OP_ORG: - case OP_ADR: - case OP_DS: - case OP_KND: - case OP_VER: - case OP_ALI: - case OP_LKV: - case OP_DO: - case OP_EQU: - case OP_EQ: - case OP_GEQ: - operand = number_operand(YYCURSOR); - break; - case OP_TYP: - operand = type_operand(YYCURSOR); - break; - case OP_OVR: - operand = ovr_operand(YYCURSOR); - break; - case OP_POS: - case OP_LEN: { - std::string tmp = label_operand(YYCURSOR, false); - if (!tmp.empty()) operand = std::move(tmp); - break; - } - case OP_KBD: { - std::string tmp = string_operand(YYCURSOR, false); - if (!tmp.empty()) operand = std::move(tmp); - break; - } - - case OP_CMD: - operand = std::string(YYCURSOR); - break; - - default: - no_operand(YYCURSOR); - break; - } - - - void evaluate(label_t label, opcode_t opcode, operand_t operand); - - evaluate(label, opcode, operand); + evaluate(label, opcode, YYCURSOR); }