aboutsummaryrefslogtreecommitdiff
path: root/src/parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/parse.c')
-rw-r--r--src/parse.c332
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
+*/