diff --git a/Makefile b/Makefile index 04d1d73..da5749f 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ clean: o: mkdir o -merlin-link: o/link.o o/mapped_file.o o/omf.o o/set_file_type.o afp/libafp.a +merlin-link: o/main.o o/link.o o/script.o o/mapped_file.o o/omf.o o/set_file_type.o afp/libafp.a $(LINK.o) $^ $(LDLIBS) -o $@ o/mapped_file.o : mapped_file.cpp mapped_file.h unique_resource.h diff --git a/link.cpp b/link.cpp index 883fbc5..baa478c 100644 --- a/link.cpp +++ b/link.cpp @@ -8,21 +8,15 @@ #include #include -/* old version of stdlib have this stuff in utility */ -#if __has_include() -#define HAVE_CHARCONV -#include -#endif #include #include #include #include -#include +#include #include #include -#include #include @@ -31,6 +25,7 @@ #include "omf.h" #include "rel.h" +#include "link.h" void save_omf(const std::string &path, std::vector &segments, bool compress, bool expressload); int set_file_type(const std::string &path, uint16_t file_type, uint32_t aux_type, std::error_code &ec); @@ -40,35 +35,41 @@ void set_file_type(const std::string &path, uint16_t file_type, uint32_t aux_typ typedef std::basic_string_view byte_view; -struct symbol { - std::string name; - std::string file; - uint32_t value = 0; - unsigned id = 0; - unsigned count = 0; - - bool absolute = false; - bool defined = false; -}; - - -std::unordered_map symbol_map; -std::vector symbol_table; struct pending_reloc : public omf::reloc { unsigned id = 0; }; -std::vector relocations; -std::vector segments; +struct cookie { + std::string file; + std::vector remap; + + uint32_t begin = 0; + uint32_t end = 0; +}; + + +namespace { + + + std::unordered_map symbol_map; + std::vector symbol_table; + + std::vector relocations; + std::vector segments; + + +} + /* nb - pointer may be invalidated by next call */ -symbol *find_symbol(const std::string &name) { +symbol *find_symbol(const std::string &name, bool insert) { auto iter = symbol_map.find(name); if (iter != symbol_map.end()) return &symbol_table[iter->second]; + if (!insert) return nullptr; unsigned id = symbol_table.size(); symbol_map.emplace(name, id); @@ -81,16 +82,7 @@ symbol *find_symbol(const std::string &name) { -struct cookie { - std::string file; - std::vector remap; - //std::vector> zero; - - uint32_t begin = 0; - uint32_t end = 0; -}; - -void process_labels(byte_view &data, cookie &cookie) { +static void process_labels(byte_view &data, cookie &cookie) { for(;;) { assert(data.size()); @@ -144,7 +136,7 @@ void process_labels(byte_view &data, cookie &cookie) { } -void process_reloc(byte_view &data, cookie &cookie) { +static void process_reloc(byte_view &data, cookie &cookie) { auto &seg = segments.back(); @@ -254,21 +246,8 @@ void process_reloc(byte_view &data, cookie &cookie) { } } -/* -void add_libraries() { - auto iter = libs.begin(); - auto end = libs.end(); - for(;;) { - - - - } -} -*/ - - -void process_unit(const std::string &path) { +static void process_unit(const std::string &path) { cookie cookie; /* skip over relocs, do symbols first */ @@ -327,7 +306,7 @@ void process_unit(const std::string &path) { } -void resolve(void) { +static void resolve(void) { /* this needs to be updated if supporting multiple segments */ auto &seg = segments.back(); @@ -377,7 +356,7 @@ static void print_symbols2(void) { } } -void print_symbols(void) { +static void print_symbols(void) { if (symbol_table.empty()) return; @@ -402,113 +381,21 @@ void print_symbols(void) { } +void finish(void) { + resolve(); + print_symbols(); -void usage(int ex) { + try { + save_omf(save_file, segments, compress, express); + set_file_type(save_file, 0xb3, 0x0000); + } catch (std::exception &ex) { + errx(EX_OSERR, "%s: %s", save_file.c_str(), ex.what()); + } - fputs("merlin-link [-o outfile] infile...\n", stderr); - exit(ex); } -/* older std libraries lack charconv and std::from_chars */ -bool parse_number(const char *begin, const char *end, uint32_t &value, int base = 10) { - -#if defined(HAVE_CHARCONV) - auto r = std::from_chars(begin, end, value, base); - if (r.ec != std::errc() || r.ptr != end) return false; -#else - auto xerrno = errno; - errno = 0; - char *ptr = nullptr; - value = std::strtoul(begin, &ptr, base); - std::swap(errno, xerrno); - if (xerrno || ptr != end) { - return false; - } -#endif - - return true; -} - -static void add_define(std::string str) { - /* -D key[=value] - value = 0x, $, % or base 10 */ - - uint32_t value = 0; - - auto ix = str.find('='); - if (ix == 0) usage(EX_USAGE); - if (ix == str.npos) { - value = 1; - } else { - - int base = 10; - auto pos = ++ix; - - char c = str[pos]; /* returns 0 if == size */ - - switch(c) { - case '%': - base = 2; ++pos; break; - case '$': - base = 16; ++pos; break; - case '0': - c = str[pos+1]; - if (c == 'x' || c == 'X') { - base = 16; pos += 2; - } - break; - } - if (!parse_number(str.data() + pos, str.data() + str.length(), value, base)) - usage(EX_USAGE); - - str.resize(ix-1); - } - - - symbol *e = find_symbol(str); - if (e->defined && e->absolute && e->value == value) return; - - if (e->defined) { - warnx("%s previously defined", str.c_str()); - return; - } - - e->defined = true; - e->absolute = true; - e->file = "-D"; - e->value = value; -} - - -int main(int argc, char **argv) { - - int c; - std::string gs_out = "gs.out"; - bool express = true; - bool compress = true; - - - while ((c = getopt(argc, argv, "o:D:XC")) != -1) { - switch(c) { - case 'o': - gs_out = optarg; - break; - case 'X': express = false; break; - case 'C': compress = false; break; - case 'D': add_define(optarg); break; - case ':': - case '?': - default: - usage(EX_USAGE); - break; - } - } - - argv += optind; - argc -= optind; - - if (!argc) usage(EX_USAGE); +void process_files(int argc, char **argv) { segments.emplace_back(); for (int i = 0; i < argc; ++i) { @@ -519,15 +406,200 @@ int main(int argc, char **argv) { errx(EX_DATAERR, "%s: %s", path, ex.what()); } } - - resolve(); - print_symbols(); - - try { - save_omf(gs_out, segments, compress, express); - set_file_type(gs_out, 0xb3, 0x0000); - exit(0); - } catch (std::exception &ex) { - errx(EX_OSERR, "%s: %s", gs_out.c_str(), ex.what()); - } } + +namespace { + + unsigned lkv = 1; + unsigned ver = 2; + unsigned ftype = 0xb3; + unsigned atype = 0x0000; + unsigned kind = 0x0000; + unsigned do_level = 0; + bool end = false; + uint32_t active_bits = 1; + bool active = true; + + std::unordered_map symbol_table; + +} + +void evaluate(label_t label, opcode_t opcode, operand_t operand) { + + switch(opcode) { + case OP_DO: + if (active_bits & 0x80000000) throw std::runtime_error("too much do do"); + active_bits <<= 1; + active_bits |= std::get(operand) ? 1 : 0; + active = (active_bits & (active_bits + 1)) == 0; + return; + break; + + case OP_ELS: + if (active_bits < 2) + throw std::runtime_error("els without do"); + + active_bits ^= 0x01; + active = (active_bits & (active_bits + 1)) == 0; + return; + break; + + case OP_FIN: + active_bits >>= 1; + if (!active_bits) { + active = 1; + throw std::runtime_error("fin without do"); + } + active = (active_bits & (active_bits + 1)) == 0; + + return; + break; + } + if (!active) return; + + switch(opcode) { + + case OP_END: + if (!end && lkv == 2) { + /* finish up */ + segments.pop_back(); + finish(); + } + end = true; + break; + + case OP_DAT: { + /* 29-DEC-88 4:18:37 PM */ + time_t t = time(nullptr); + struct tm tm = localtime(&t); + char buffer[32]; + + strftime(buffer, sizeof(buffer), "%d-%b-%y %H:%M:%S %p", tm); + for(char &c : buffer) c = std::toupper(c); + + printf(stdout, "%s\n", buffer); + break; + } + + + case OP_TYP: + ftype = std::get(operand); + break; + case OP_ADR: + atype = std::get(operand); + break; + + case OP_KND: + kind = std::get(operand); + break; + + case OP_LKV: + /* specify linker version */ + /* 0 = binary, 1 = Linker.GS, 2 = Linker.XL, 3 = convert to OMF object file */ + + switch (std::get(operand)) { + case 0: throw std::runtime_error("binary linker not supported"); + case 3: throw std::runtime_error("object file linker not supported"); + case 1: + case 2: + lkv = std::get(operand); + break; + default: + throw std::runtime_error("bad linker version"); + } + break; + + case OP_VER: + /* OMF version, 1 or 2 */ + if (std::get(operand) != 2) + throw std::runtime_error("bad OMF version"); + break; + + + case OP_LNK: + if (end) throw std::runtime_error("link after end"); + //link_unit(std::get(operand)); + break; + + 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) { + auto &seg = segments.back(); + seg.segname = std::get(operand); + seg.kind = kind; + finish(); + end = true; + } + if (lkv == 2) { + auto &seg = segments.back(); + seg.segname = std::get(operand); + seg.kind = kind; + + /* if this is the first segment, also save the + /* add a new segment */ + segments.emplace_back(); + } + + + + break; + + + case OP_ASM: + default: + throw std::runtime_error("opcode not yet supported"); + } + +} + +void process_script(const char *path) { + + extern void parse_line(const char *); + + FILE *fp; + fp = fopen(path, "r"); + if (!fp) { + warn("Unable to open %s", path); + return -1; + } + + int no = 1; + int errors = 0; + char *line = NULL; + size_t cap = 0; + for(;; ++no) { + + ssize_t len = getline(&line, &cap, fp); + if (len == 0) break; + if (len < 0) { + warn("read error"); + ++errors; + break; + } + /* strip trailing ws */ + while (len && isspace(line[len-1])) --len; + line[len] = 0; + if (len == 0) continue; + + try { + parse_line(line); + } catch (std::exception &ex) { + if (~active & 0x01) continue; + + fprintf(stderr, "%s in line: %d\n", ex.what(), no); + fprintf(stderr, "%s\n", line); + if (++errors >= 10) { + fputs("Too many errors, aborting\n", stderr); + break; + } + } + } + fclose(fp); + free(line); + exit(errors ? EX_DATAERR : 0); +} + diff --git a/link.h b/link.h new file mode 100644 index 0000000..051ad26 --- /dev/null +++ b/link.h @@ -0,0 +1,31 @@ +#ifndef link_h +#define link_h + +#include +#include + +extern bool verbose; +extern bool compress; +extern bool express; +extern std::string save_file; + + +struct symbol { + std::string name; + std::string file; + uint32_t value = 0; + unsigned id = 0; + unsigned count = 0; + + bool absolute = false; + bool defined = false; +}; + + +void process_script(const char *argv); +void process_files(int argc, char **argv); + + +symbol *find_symbol(const std::string &name, bool insert = true); + +#endif \ No newline at end of file diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..f4fc1b2 --- /dev/null +++ b/main.cpp @@ -0,0 +1,157 @@ + +#include +#include +#include + +#include +#include +#include +#include +#include + +/* old version of stdlib have this stuff in utility */ +#if __has_include() +#define HAVE_CHARCONV +#include +#endif + +#include +#include +#include + +#include "link.h" + +static void usage(int ex) { + + fputs( + "merlin-link [options] infile...\n" + "\noptions:\n" + "-C inhibit SUPER compression\n" + "-D symbol=value define symbol\n" + "-X inhibit expressload segment\n" + "-o outfile specify output file (default gs.out)\n" + "-v be verbose\n" + "\n", + stderr); + + exit(ex); +} + +/* older std libraries lack charconv and std::from_chars */ +static bool parse_number(const char *begin, const char *end, uint32_t &value, int base = 10) { + +#if defined(HAVE_CHARCONV) + auto r = std::from_chars(begin, end, value, base); + if (r.ec != std::errc() || r.ptr != end) return false; +#else + auto xerrno = errno; + errno = 0; + char *ptr = nullptr; + value = std::strtoul(begin, &ptr, base); + std::swap(errno, xerrno); + if (xerrno || ptr != end) { + return false; + } +#endif + + return true; +} + +static void add_define(std::string str) { + /* -D key[=value] + value = 0x, $, % or base 10 */ + + uint32_t value = 0; + + auto ix = str.find('='); + if (ix == 0) usage(EX_USAGE); + if (ix == str.npos) { + value = 1; + } else { + + int base = 10; + auto pos = ++ix; + + char c = str[pos]; /* returns 0 if == size */ + + switch(c) { + case '%': + base = 2; ++pos; break; + case '$': + base = 16; ++pos; break; + case '0': + c = str[pos+1]; + if (c == 'x' || c == 'X') { + base = 16; pos += 2; + } + break; + } + if (!parse_number(str.data() + pos, str.data() + str.length(), value, base)) + usage(EX_USAGE); + + str.resize(ix-1); + } + + + symbol *e = find_symbol(str); + if (e->defined && e->absolute && e->value == value) return; + + if (e->defined) { + warnx("%s previously defined", str.c_str()); + return; + } + + e->defined = true; + e->absolute = true; + e->file = "-D"; + e->value = value; +} + +/* .ends_with() is c++20 */ +static bool is_S(std::string_view sv) { + size_t s = sv.size(); + // && is a sequence point. + return s >= 2 && std::toupper(sv[--s]) == 'S' && sv[--s] == '.'; +} + + +bool verbose = false; +std::string save_file = "gs.out"; +bool express = true; +bool compress = true; + +int main(int argc, char **argv) { + + int c; + bool script = false; + + while ((c = getopt(argc, argv, "o:D:XCSv")) != -1) { + switch(c) { + case 'o': + save_file = optarg; + break; + case 'X': express = false; break; + case 'C': compress = false; break; + case 'D': add_define(optarg); break; + case 'v': verbose = true; + case ':': + case '?': + default: + usage(EX_USAGE); + break; + } + } + + argv += optind; + argc -= optind; + + if (!argc) usage(EX_USAGE); + + if (script && argc > 1) usage(EX_USAGE); + if (argc == 1 && is_S(*argv)) script = true; + + if (script) process_script(*argv); + else process_files(argc, argv); + + exit(0); +} \ No newline at end of file diff --git a/script.re2c b/script.re2c index d27e5fc..e53af9b 100644 --- a/script.re2c +++ b/script.re2c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -18,6 +19,8 @@ #include +#include "script.h" + /*!re2c re2c:define:YYCTYPE = char; @@ -29,73 +32,67 @@ eof = "\x00"; */ -enum { - CMD_NONE = 0, - #define x(op) CMD_##op, - #include "ops.h" - #undef x - CMD_EQ -}; +namespace { + std::unordered_map opcodes = { + #define x(op) { #op, OP_##op }, -static std::unordered_map commands = { - #define x(op) { #op, CMD_##op }, + #include "ops.h" + #undef x - #include "ops.h" - #undef x - - /* aliases */ - { "AUX", CMD_ADR }, - { "REZ", CMD_RES }, - { "LIN", CMD_LNK }, - { "KIN", CMD_KND }, - { "=", CMD_EQ } -}; + /* aliases */ + { "AUX", OP_ADR }, + { "REZ", OP_RES }, + { "LIN", OP_LNK }, + { "KIN", OP_KND }, + { "=", OP_EQ } + }; -static std::unordered_map types = { + 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 }, - -}; + { "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 }, + }; +} static uint32_t number_operand(const char *YYCURSOR, bool required = true) { - char *iter = YYCURSOR; + const char *iter = YYCURSOR; + const char *YYMARKER = nullptr; uint32_t rv = 0; /*!re2c * { throw std::invalid_argument("bad operand"); } @@ -146,7 +143,8 @@ exit: static uint32_t type_operand(const char *YYCURSOR, bool required = true) { - char *iter = YYCURSOR; + const char *iter = YYCURSOR; + const char *YYMARKER = nullptr; uint32_t rv = 0; /*!re2c * { throw std::invalid_argument("bad operand"); } @@ -189,10 +187,10 @@ static uint32_t type_operand(const char *YYCURSOR, bool required = true) { std::string s(iter, YYCURSOR); for(char &c : s) c = std::toupper(c); auto iter = types.find(s); - if (iter == types.end) { + if (iter == types.end()) { throw std::invalid_argument("bad operand"); } - rv = *iter; + rv = iter->second; } */ exit: @@ -205,7 +203,8 @@ exit: static int x_number_operand(const char *YYCURSOR) { - char *iter = YYCURSOR; + const char *iter = YYCURSOR; + const char *YYMARKER = nullptr; uint32_t rv = 0; /*!re2c * { throw std::invalid_argument("bad operand"); } @@ -247,24 +246,28 @@ exit: } static std::string x_label_operand(const char *YYCURSOR) { - char *iter = YYCURSOR; + const char *iter = YYCURSOR; + const char *YYMARKER = nullptr; std::string rv; /*!re2c * { throw std::invalid_argument("bad operand"); } ident { std::string s(iter, YYCURSOR); - //look up symbol, verify it's an absolute value, etc + goto exit; } */ exit: char c = *YYCURSOR; - if (isspace(c) || c == 0) return rv; + 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) { - char *iter = YYCURSOR; + const char *iter = YYCURSOR; std::string rv; /*!re2c * { throw std::invalid_argument("bad operand"); } @@ -285,17 +288,18 @@ exit: static int ovr_operand(const char *YYCURSOR) { int rv = 0; + const char *YYMARKER = nullptr; /*!re2c * { throw std::invalid_argument("bad operand"); } [;*] | eof { - return 1; + return OVR_NONE; } 'ALL' { - rv = -1; + rv = OVR_ALL; } 'OFF' { - rv = 0; + rv = OVR_OFF; } */ @@ -307,7 +311,8 @@ static int ovr_operand(const char *YYCURSOR) { static std::string label_operand(const char *YYCURSOR, bool required = true) { std::string rv; - char *iter = YYCURSOR; + const char *iter = YYCURSOR; + const char *YYMARKER = nullptr; /*!re2c * { throw std::invalid_argument("bad operand"); } [;*] | eof { @@ -320,6 +325,7 @@ static std::string label_operand(const char *YYCURSOR, bool required = true) { } */ +exit: char c = *YYCURSOR; if (isspace(c) || c == 0) return rv; @@ -329,7 +335,8 @@ static std::string label_operand(const char *YYCURSOR, bool required = true) { static std::string path_operand(const char *YYCURSOR, bool required = true) { std::string rv; - char *iter = YYCURSOR; + const char *iter = YYCURSOR; + const char *YYMARKER = nullptr; /*!re2c * { throw std::invalid_argument("bad operand"); } [;*] | eof { @@ -348,6 +355,7 @@ static std::string path_operand(const char *YYCURSOR, bool required = true) { */ +exit: char c = *YYCURSOR; if (isspace(c) || c == 0) return rv; @@ -358,7 +366,7 @@ static std::string path_operand(const char *YYCURSOR, bool required = true) { static void no_operand(const char *YYCURSOR) { /*!re2c * { throw std::invalid_argument("bad operand"); } - [;*] | eof { return } + [;*] | eof { return; } */ } @@ -366,7 +374,8 @@ static void no_operand(const char *YYCURSOR) { static std::string string_operand(const char *YYCURSOR, bool required = true) { std::string rv; - char *iter = YYCURSOR; + const char *iter = YYCURSOR; + const char *YYMARKER = nullptr; /*!re2c * { throw std::invalid_argument("bad operand"); } [;*] | eof { @@ -378,7 +387,7 @@ static std::string string_operand(const char *YYCURSOR, bool required = true) { goto exit; } */ - +exit: char c = *YYCURSOR; if (isspace(c) || c == 0) return rv; throw std::invalid_argument("bad operand"); @@ -386,21 +395,24 @@ static std::string string_operand(const char *YYCURSOR, bool required = true) { -static void parse_line(const char *YYCURSOR) { +void parse_line(const char *YYCURSOR) { - unsigned cmd = 0; - std::string label; + label_t label; + opcode_t opcode = OP_NONE; + operand_t operand; const char *iter = YYCURSOR; + const char *YYMARKER = nullptr; + /*!re2c - * { throw std::invalid_argument("bad label") } + * { throw std::invalid_argument("bad label"); } [;*] | eof { return; } - ws { goto opcode } + ws { goto opcode; } ident / (ws|eof) { - label(iter, YYCURSOR); + label = std::string(iter, YYCURSOR); goto opcode; } @@ -409,27 +421,26 @@ static void parse_line(const char *YYCURSOR) { opcode: - while (isspace(*YYCURSOR)) ++YYCURSOR; iter = YYCURSOR; /*!re2c * { throw std::invalid_argument("bad opcode"); } - [;*]|eof { return 0; } + [;*]|eof { return; } - '=' / (ws|eof) { cmd = CMD_EQ; goto operand; } + '=' / (ws|eof) { opcode = OP_EQ; goto operand; } [A-Za-z]+ / (ws|eof) { - size_t = l YYCURSOR - iter; + size_t l = YYCURSOR - iter; if (l > 3) l = 3; std::string s(iter, iter + l); - for (char &c in s): c = std::toupper(c); - auto iter = commands.find(s); - if (!iter == commands.end()) { + for (char &c : s) c = std::toupper(c); + auto iter = opcodes.find(s); + if (iter == opcodes.end()) { throw std::invalid_argument("bad opcode"); } - cmd = *iter; + opcode = iter->second; goto operand; } */ @@ -439,51 +450,53 @@ operand: while (isspace(*YYCURSOR)) ++YYCURSOR; iter = YYCURSOR; - std::string str_operand; - long int_operand; - switch(cmd) { - case CMD_LNK: - case CMD_PUT: - case CMD_ASM: - case CMD_SAV: - case CMD_LIB: - case CMD_IF: - case CMD_PFX: - case CMD_IMP: - case CMD_RES: - case CMD_FIL: - str_operand = path_operand(YYCURSOR); + 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 CMD_ORG: - case CMD_ADR: - case CMD_DS: - case CMD_KND: - case CMD_VER: - case CMD_ALI: - case CMD_LKV: - case CMD_DO: - case CMD_EQU: - case CMD_EQ: - case CMD_GEQ: - int_operand = number_operand(YYCURSOR); + 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 CMD_TYP: - int_operand = type_operand(YYCURSOR); + case OP_TYP: + operand = type_operand(YYCURSOR); break; - case CMD_OVR: - int_operand = ovr_operand(YYCURSOR); + case OP_OVR: + operand = ovr_operand(YYCURSOR); break; - case CMD_POS: - case CMD_LEN: - str_operand = label_operand(YYCURSOR, false); + case OP_POS: + case OP_LEN: { + std::string tmp = label_operand(YYCURSOR, false); + if (!tmp.empty()) operand = std::move(tmp); break; - case CMD_KBD: - str_operand = string_operand(YYCURSOR, false); + } + case OP_KBD: { + std::string tmp = string_operand(YYCURSOR, false); + if (!tmp.empty()) operand = std::move(tmp); break; + } - case CMD_CMD: - str_operand = string(YYCURSOR); + case OP_CMD: + str_operand = std::string(YYCURSOR); break; default: @@ -491,143 +504,11 @@ operand: break; } - switch(cmd) { - - case CMD_NONE: - case CMD_NOL: /* asm: default list off */ - case CMD_PUT: /* check if source file is outdated */ - case CMD_OVR: /* override outdated check and force assembly */ - case CMD_FAS: /* fast linker. only one SAV allowed */ - /* nop */ - break; - - case CMD_LNK: - /* link file ... */ - break; - case CMD_ORG: - /* set the link origin. also used as aux type */ - break; - case CMD_ADR: - /* set the file aux type */ - break; - - case CMD_SAV: - /* save linked file. for xl linker, specifies segment name */ - break; - - case CMD_TYP: - /* set the file type */ - break; - - case CMD_EXT: - /* print addresses of all resolved externals (not just errors) - disabled after each SAV - */ - break; - case CMD_ENT: - /* print the entry list */ - /* flag symbol w ? if unused */ - break; - case CMD_DAT: - /* print the current date and time */ - break; - - case CMD_END: - /* end of command file (optional) */ - break; - - case CMD_LIB: - /* search directory for unresolved symbols */ - break; - - case CMD_LKV: - /* specify linker version */ - /* 0 = binary, 1 = Linker.GS, 2 = Linker.XL, 3 = convert to OMF object file */ - switch (int_operand) { - case 0: throw std::runtime_error("binary linker not supported"); - case 3: throw std::runtime_error("object file linker not supported"); - case 1: - case 2: - /* default file type = S16 */ - break; - default: - throw std::runtime_error("bad linker version"); - } - break; - - case CMD_VER: - /*specify OMF version. 1 or 2 */ - break; - - case CMD_KND: - /* set the OMF kind flag */ - /* 8-bit for v 1, 16-bit for v2 */ - break; - - case CMD_ALI: - /* OMF align field. default = 0 */ - break; - - case CMD_DS: - /* OMF RESSPC field */ - break; - - - case CMD_LEN: - /* Puts "LABEL" in symbol dictionary a san ENTry whose value is equal to the number of bytes of the last linked file. */ - break; - case CMD_POS: - - - - case CMD_ASM: - default: - throw std::runtime_error("opcode not supported"); - } - + void evaluate(label_t label, opcode_t opcode, operand_t operand); + evaluate(label, opcode, opcode); } -int process_link_file(const std::string &path) { - FILE *fp; - fp = fopen(path, "r"); - if (!fp) { - warn("Unable to open %s", path.c_str()); - return -1; - } - int no = 1; - int errors = 0; - const char *line = NULL; - size_t cap = 0; - for(;; ++no) { - - ssize_t len = getline(&line, &cap, fp); - if (len == 0) break; - if (len < 0) { - warn("read error"); - ++errors; - break; - } - /* strip trailing ws */ - while (len && isspace(line[len-1])) --len; - line[len] = 0; - if (len == 0) continue; - - try { - parse_line(line); - } catch (std::exception &ex) { - fprintf(stderr, "%s in line: %d\n", ex.what(), no); - fprintf(stderr, "%s\n", line); - if (++errors >= 10) { - fputs("Too many errors, aborting\n", stderr); - break; - } - } - } - fclose(fp); - free(line); - return errors ? -1 : 0; -}