From e0b6ba2c315b8d09b92fdddd8aaa5f73548bcf11 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Tue, 9 Aug 2016 08:17:58 -0400 Subject: [PATCH] load trap - process entire (mapped) file with one-shot. --- bin/loadtrap.rl | 332 ++++++++++++++---------------------------------- 1 file changed, 96 insertions(+), 236 deletions(-) diff --git a/bin/loadtrap.rl b/bin/loadtrap.rl index dd864f2..0456bd3 100644 --- a/bin/loadtrap.rl +++ b/bin/loadtrap.rl @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Kelvin W Sherlock + * Copyright (c) 2013, 2016, Kelvin W Sherlock * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -24,261 +24,121 @@ * */ -#include -#include -#include +%%{ -#include -#include +machine load_traps; +alphtype unsigned char; -namespace _loadtrap_rl { -#if __APPLE__ && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1050 - #define _GETDELIM_GROWBY 128 /* amount to grow line buffer by */ - #define _GETDELIM_MINLEN 4 /* minimum line buffer size */ - - ssize_t getdelim(char ** lineptr, size_t * n, int delimiter, FILE * stream) { - char *buf, *pos; - int c; - ssize_t bytes; - - if (lineptr == NULL || n == NULL) { - errno = EINVAL; - return -1; - } - if (stream == NULL) { - errno = EBADF; - return -1; - } - - /* resize (or allocate) the line buffer if necessary */ - buf = *lineptr; - if (buf == NULL || *n < _GETDELIM_MINLEN) { - buf = (char*)realloc(*lineptr, _GETDELIM_GROWBY); - if (buf == NULL) { - /* ENOMEM */ - return -1; - } - *n = _GETDELIM_GROWBY; - *lineptr = buf; - } - - /* read characters until delimiter is found, end of file is reached, or an - error occurs. */ - bytes = 0; - pos = buf; - while ((c = getc(stream)) != EOF) { - if (bytes + 1 >= SSIZE_MAX) { - errno = EOVERFLOW; - return -1; - } - bytes++; - if (bytes >= *n - 1) { - buf = (char*)realloc(*lineptr, *n + _GETDELIM_GROWBY); - if (buf == NULL) { - /* ENOMEM */ - return -1; - } - *n += _GETDELIM_GROWBY; - pos = buf + bytes - 1; - *lineptr = buf; - } - - *pos++ = (char) c; - if (c == delimiter) { - break; - } - } - - if (ferror(stream) || (feof(stream) && (bytes == 0))) { - /* EOF, or an error from getc(). */ - return -1; - } - - *pos = '\0'; - return bytes; - } -#endif - - - ssize_t getline(char ** lineptr, size_t * n, FILE * stream) { -#if __APPLE__ && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1050 - return getdelim(lineptr, n, '\n', stream); -#else - return ::getline(lineptr, n, stream); -#endif - } +action reset { + negative = false; + value = 0; + key.clear(); + scratch.clear(); } -namespace { - // private... - %%{ - - machine lexer; - action addx { - int x = fc; - if (x >= '0' && x <= '9') x = x -'0'; - else x = (x | 0x20) - 'a' + 10; - value = (value << 4) + x; +action commit { + bool ok = true; + + if (!scratch.empty()) { + auto iter = table.find(scratch); + if (iter == table.end()) { + fprintf(stderr, "Undefined reference: %s\n", scratch.c_str()); + ok = false; } - - ws = [ \t]; - - value = - '0x' xdigit+ @addx - | - '$' xdigit+ @addx - | - '-'? @{ negative = true; } - digit+ @{value = value * 10 + (fc - '0'); } - | - [A-Za-z_] @{ stringValue.push_back(fc); } - [A-Za-z0-9_]+ @{ stringValue.push_back(fc); } - ; - - - name = - [A-Za-z0-9_]+ @{ - name.push_back(fc); - } - ; - - main := - - name - ws* - '=' - ws* - value - ; - - write data; - }%% - - - - bool ParseLine(const char *p, const char *pe, std::map &map) - { - - // trap = number - // or trap = [previously defined trap] - - std::string name; - std::string stringValue; - uint32_t value; - bool negative = false; - - value = 0; - const char *eof = pe; - int cs; - - %%write init; - %%write exec; - - if (cs < %%{ write first_final; }%% ) - { - return false; - } - if (negative) value = (-value) & 0xffff; - - // name lookup - if (!stringValue.empty()) - { - auto iter = map.find(stringValue); - if (iter == map.end()) - { - fprintf(stderr, "Undefined trap: %s\n", stringValue.c_str()); - return false; - } - value = iter->second; - } - - #if 0 - // if loading globals, wouldn't need to do this... - if (value > 0xafff || value < 0xa000) - { - fprintf(stderr, "Invalid trap number: $%04x\n", value); - return false; - } -#endif - - map.emplace(name, (uint16_t)value); - - - return true; + else value = iter->second; } + if (negative) value = -value; - - + if (ok) table.emplace(std::move(key), value); } +eol = [\r\n] ${ line++; }; +ws = [ \t]; + +error := [^\r\n]* eol $reset ${ fnext main; }; + +comment = '#' [^\r\n]*; + + +word = [A-Za-z_][A-Za-z_0-9]*; +key = word ${ key.push_back(fc); }; + +base16 = + [0-9] ${value = (value << 4) + fc - '0'; } + | [A-Fa-f] ${value = (value << 4) + (fc | 0x20) - 'a' + 10; } + ; + +base10 = [0-9]+ ${ value = (value * 10) + fc - '0'; }; + +decnumber = ( '-' ${ negative = true; } )? base10+; +hexnumber = ('$' | '0x') base16+; + +number = decnumber | hexnumber; + +value = number | word ${ scratch.push_back(fc); }; + + +line = + ws* ( key ws* '=' ws* value %commit %reset ws*)? comment? eol + ; + + main := line* + $err{ + fprintf(stderr, "Unexpected character '%c' on line %d\n", fc, line); + fnext error; + }; + +}%%; + + +namespace { + %% write data; +} + +#include +#include +#include + +#include +#include + namespace Debug { - void LoadTrapFile(const std::string &path, std::map &map) - { - FILE *fp; + void LoadTrapFile(const std::string &path, std::map &table) { + int cs; + const unsigned char *p; + const unsigned char *pe; + const unsigned char *eof; + int line = 1; - fp = fopen(path.c_str(), "r"); - if (!fp) - { - fprintf(stderr, "Unable to open trap file %s\n", path.c_str()); + int value = 0; + bool negative = false; + std::string key; + std::string scratch; + + mapped_file mf; + try { + mf.open(path, mapped_file::readonly); + } catch (const std::exception &ex) { + //fprintf(stderr, "### %s: %s\n", path.c_str(), ex.what()); return; } + %% write init; + p = mf.cbegin(); + pe = mf.cend(); + eof = nullptr; - /* - * getline(3) is 2008 posix. it allocates (and resizes as appropriate) - * the buffer. - * - */ - char *lineBuffer = NULL; - size_t lineSize = 0; + for (int i = 0; i < 2; ++i) { + %% write exec; - for(;;) - { - char *line; - ssize_t length; - - length = _loadtrap_rl::getline(&lineBuffer, &lineSize, fp); - if (!length) continue; //? - if (length < 0) break; // eof or error. - - line = lineBuffer; - - // skip any leading space. - while (length && isspace(*line)) - { - ++line; - --length; - } - if (!length) continue; - - // comments - if (*line == '#') continue; - - - // strip any trailing space. - // (will be \n terminated unless there was no \n) - while (length && isspace(line[length - 1])) - { - line[--length] = 0; - } - if (!length) continue; - - if (!ParseLine(line, line + length, map)) - { - fprintf(stderr, "Error in trap definition: %s\n", line); - } + p = (const unsigned char *)"\n"; + pe = eof = p+1; } - - fclose(fp); } - - - } - #ifdef TEST int main(int argc, char **argv) @@ -289,7 +149,7 @@ int main(int argc, char **argv) std::map map; Debug::LoadTrapFile(f, map); - for(const auto kv : map) + for(const auto &kv : map) { printf("%s -> %04x\n", kv.first.c_str(), kv.second); } @@ -298,4 +158,4 @@ int main(int argc, char **argv) return 0; } -#endif +#endif \ No newline at end of file