--- /dev/null
+/*
+ * parser.c -- part of ZilUtils/ZilAsm
+ *
+ * Copyright (C) 2016 Jason Self <j@jxself.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ */
+
+#include <stdio.h> /* fopen, fgets */
+#include <string.h> /* strlen */
+
+#include "parser.h"
+#include "directives.h"
+#include "opcodes.h"
+#include "labels.h"
+
+#define iscomment(c) ((c) == '#')
+#define isbindigit(c) ((c) == '0' || (c) == '1')
+
+/* !!! TODO !!! */
+#define fatal_error(errmsg)
+#define PC NULL
+
+void checksep(const char *p)
+{
+ if (!*p || iscomment(*p) || isspace(*p)) return;
+ fatal_error("wrong chars");
+}
+
+const char *pass_spaces(const char *p)
+{
+ while(p && isspace(*p)) p++;
+ return (p && *p) ? p : NULL;
+}
+
+const char *pass_alnums(const char *p)
+{
+ while(p && isalnum(*p)) p++;
+ return (p && *p) ? p : NULL;
+}
+
+int tryparse_directive(const char *p)
+{
+ if (*p != '.')
+ return 0;
+ const char *a = p+1;
+ const char *b = pass_alnums(a);
+ checksep(b);
+ Directive_handler f = directive_lookup(a, b - a);
+ if (!f) return 0;
+ return (*f)(b);
+}
+
+int tryparse_assignment(const char *a, const char *b, const char *c)
+{
+ return 0;
+}
+
+int tryparse_label(const char *a, const char *b, const char *c)
+{
+ if (*(c+1) != ':') {
+ symtable_add2(Local_labels, a, b - a, PC);
+ } else if (*(c+2) != ':') {
+ symtable_add2(Global_labels, a, b - a, PC);
+ } else {
+ fatal_error("wrong label type");
+ }
+
+ while (*c++ == ':');
+ if (*c && ((c = pass_spaces(c)) != NULL) && *c)
+ return tryparse_instruction(c);
+ return 1;
+}
+
+int tryparse_name(const char *a)
+{
+ const char *b = pass_alnums(a);
+ const char *c = pass_spaces(b);
+
+ if (!c) return 0;
+ if (*c == '=') return tryparse_assignment(a, b, c + 1);
+ if (*c == ':') return tryparse_label(a, b, c);
+ return 0;
+}
+
+int tryparse_instruction(const char *a)
+{
+ const char *b = pass_alnums(a);
+ ZOpcode *op = symtable_lookup2(Opcodes, a, b - a);
+ if (!op) return 0;
+ ZOpcode_flags flags = op->flags;
+ /* !!! TODO !!! */
+ return 0;
+}
+
+/*
+ * Line can be one from: Comment, Global label, Local label, Directive, Name=Value, Instruction
+ */
+int parse_line(const char *p)
+{
+ for (; *p; p++) {
+ char c = *p;
+ int n;
+ if (isspace(c)) continue;
+ if (iscomment(c)) return 0;
+ if (n = tryparse_directive(p)) return n;
+ if (n = tryparse_name(p)) return n; // ..label or assignment
+ if (n = tryparse_instruction(p)) return n;
+ fatal_error("wrong line");
+ }
+ return 0;
+}
+
+int parse_file(const char *filename)
+{
+ FILE *fp = fopen(filename, "r");
+ if (!fp) fatal_error("wrong file");
+
+ const int MAX_LINESIZE = 1024;
+ char line[MAX_LINESIZE];
+ int newline_missing = 0;
+
+ while (fgets(line, MAX_LINESIZE, fp)) {
+ if (newline_missing) fatal_error("line too long");
+
+ int n = strlen(line);
+ if (!n) continue;
+
+ parse_line(line);
+
+ newline_missing = (line[n-1] != '\n');
+ }
+
+ close(fp);
+}
+
+/*
+
+line_passed() {
+ skip_spaces();
+ return (current_token == LINE_END || current_token == LINE_COMMENT);
+}
+
+if (line_passed()) continue;
+if (current_token == DIRECTIVE) {
+ if (!try_next_token(NAME))
+ fatal_error("directive contains incorrect chars")
+ handler = get_directive_handler(current_token);
+ if (!handler)
+ fatal error("unknown directive");
+ (*handler)(remaining_line);
+ if (line_passed()) continue;
+ fatal_error("unexpected line tail");
+} else if (current_token == NAME) {
+ skip_spaces();
+ if (current_token == ASSIGNMENT)
+}
+
+
+*/