diff options
Diffstat (limited to 'src/parse.c')
-rw-r--r-- | src/parse.c | 332 |
1 files changed, 332 insertions, 0 deletions
diff --git a/src/parse.c b/src/parse.c new file mode 100644 index 0000000..abcd149 --- /dev/null +++ b/src/parse.c @@ -0,0 +1,332 @@ +/* + + casm - Simple, portable assembler + + Copyright (C) 2003-2015 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + ------------------------------------------------------------------------- + + Tokeniser. + +*/ +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> + +#include "global.h" +#include "codepage.h" +#include "parse.h" + +/* ---------------------------------------- MACROS/TYPES +*/ +typedef enum +{ + CONSUME_WS, + CONSUME_TOKEN, + FINISHED +} State; + + +/* ---------------------------------------- GLOBALS +*/ +static char error[1024]; + +static const ValueTable bool_table[] = +{ + YES_NO_ENTRIES(TRUE, FALSE), + {NULL} +}; + + + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ +static void AddToken(const char *start, const char *end, Line *line, int quoted) +{ + char *tok = Malloc(end - start + 2); + char *p; + + p = tok; + + while(start != end + 1) + { + *p++ = *start++; + } + + *p = 0; + + Trim(tok); + + /* Special case to convert single characters in quotes to their character + code. + */ + if (*tok && *(tok+1) == 0 && (quoted == '\'' || quoted == '"')) + { + char b[64]; + + snprintf(b, sizeof b, "%d", CodepageConvert(*tok)); + free(tok); + + tok = DupStr(b); + quoted = 0; + } + + line->no_tokens++; + + line->token = Realloc(line->token, (sizeof *line->token) * line->no_tokens); + + line->quoted = Realloc(line->quoted, + (sizeof *line->quoted) * line->no_tokens); + + line->token[line->no_tokens - 1] = tok; + line->quoted[line->no_tokens - 1] = quoted; +} + + +/* ---------------------------------------- INTERFACES +*/ + +int ParseLine(Line *line, const char *source) +{ + static const char *sep_chars[2] = + { + " \t:", + "," + }; + + static const char *quote_start_chars[2] = + { + "", + "\"'(" + }; + + static const char *quote_end_chars[2] = + { + "", + "\"')" + }; + + const char *p = NULL; + const char *start = NULL; + State state = CONSUME_WS; + int stage = 0; + char open_quote = 0; + char quote = 0; + int status = TRUE; + + p = source; + + line->first_column = FALSE; + line->token = NULL; + line->comment = NULL; + line->quoted = NULL; + line->no_tokens = 0; + + while(state != FINISHED) + { + switch(state) + { + case CONSUME_WS: + if (!*p) + { + state = FINISHED; + } + else if (*p == ';') + { + state = FINISHED; + line->comment = DupStr(p + 1); + Trim(line->comment); + } + else + { + const char *ptr; + + if ((ptr = strchr(quote_start_chars[stage], *p))) + { + open_quote = *p; + quote = quote_end_chars + [stage] + [ptr - quote_start_chars[stage]]; + + state = CONSUME_TOKEN; + start = ++p; + } + else + { + if (isspace((unsigned char)*p) || + strchr(sep_chars[stage], *p)) + { + p++; + } + else + { + state = CONSUME_TOKEN; + start = p; + open_quote = 0; + quote = 0; + } + } + + if (source == start && state == CONSUME_TOKEN) + { + line->first_column = TRUE; + } + } + break; + + case CONSUME_TOKEN: + if (!*p) + { + if (quote) + { + snprintf + (error, sizeof error, + "Unterminated quoted string; expected %c", quote); + + status = FALSE; + } + else if (start != p) + { + AddToken(start, p, line, FALSE); + } + + state = FINISHED; + } + else + { + if (quote) + { + if (*p == quote) + { + state = CONSUME_WS; + } + } + else if (strchr(sep_chars[stage], *p) || *p == ';') + { + state = CONSUME_WS; + } + + if (state == CONSUME_WS) + { + AddToken(start, p - 1, line, open_quote); + + if (quote) + { + open_quote = 0; + quote = 0; + p++; + } + + if ((line->no_tokens == 2 && line->first_column) || + (line->no_tokens == 1 && !line->first_column)) + { + stage = 1; + } + } + else + { + p++; + } + } + break; + + default: + break; + } + } + + return status; +} + + +void ParseFree(Line *line) +{ + int f; + + if (line->token) + { + for(f = 0; f < line->no_tokens; f++) + { + free(line->token[f]); + } + + free(line->token); + free(line->quoted); + } + + if (line->comment) + { + free(line->comment); + } + + line->token = NULL; + line->quoted = NULL; + line->comment = NULL; +} + + +const char *ParseError(void) +{ + return error; +} + +const ValueTable *ParseTable(const char *str, const ValueTable *table) +{ + while(table && table->str) + { + if (CompareString(str, table->str)) + { + return table; + } + + table++; + } + + return NULL; +} + + +int ParseTrueFalse(const char *str, int def) +{ + const ValueTable *val; + + val = ParseTable(str, bool_table); + + return val == NULL ? def : val->value; +} + + +int ParseInTable(const char *str, const char *names[]) +{ + int f; + + for(f = 0; names[f]; f++) + { + if (CompareString(str, names[f])) + { + return TRUE; + } + } + + return FALSE; +} + + + +/* +vim: ai sw=4 ts=8 expandtab +*/ |