--- /dev/null
+/*
+ * parser.c -- part of ZilUtils/ZilAsm
+ *
+ * Copyright (C) 2016, 2019 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/>
+ *
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+#include <stdlib.h>
+#include <stdio.h> /* fopen, fgets */
+#include <string.h> /* strlen */
+#include <ctype.h>
+#include <string>
+using namespace std;
+
+
+#include "header.h"
+#include "parser.h"
+
+extern "C"
+{
+#include "directives.h"
+#include "opcodes.h"
+}
+#include "labels.h"
+#include "string_table.h"
+
+
+#define iscomment(c) ((c) == ';')
+#define isbindigit(c) ((c) == '0' || (c) == '1')
+
+/* !!! TODO !!! */
+#define fatal_error(errmsg) printf(errmsg)
+#define PC NULL
+
+unsigned g_numberOfInstructions = 0;
+
+
+ZMemblock (*g_codes[MAX_NUMBER_OF_INSTRUCTIONS]);
+
+
+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_instruction (const char *a);
+
+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);
+ if (b != a)
+ {
+ int len = b ? b - a : strlen (a);
+ ZOpcode *op = (ZOpcode *) symtable_lookup2 (Opcodes, a, len);
+ if (!op)
+ return 0;
+ ZOpcode_flags flags = op->flags;
+ /* !!! TODO !!! */
+
+
+ ZMemblock *mem_additional = NULL;
+
+ switch (op->opcode)
+ {
+ case Opcode_CRLF:
+ case Opcode_PRINT:
+ case Opcode_QUIT:
+ break;
+
+ case Opcode_PRINTI:
+ case Opcode_PRINTR:
+ {
+ char *p = (char *) a + len;
+ p = (char *) pass_spaces (p);
+ if (*p == '\"')
+ {
+ p++;
+ string str;
+ while (*p != '\"')
+ {
+ str += *p;
+ ++p;
+ }
+ len = p - a;
+ mem_additional =
+ String_table::encrypt_string (str.c_str (), NULL);
+ }
+ break;
+ }
+ default:
+ fatal_error ("error! instruction not supported");
+ return 0;
+ }
+
+ int instruction_size = 1;
+ if (mem_additional)
+ instruction_size += mem_additional->used_size;
+ //printf("instruction %s", a);
+
+ g_codes[g_numberOfInstructions] = zmem_init (instruction_size);
+ zmem_putbyte (g_codes[g_numberOfInstructions], op->opcode);
+
+ if (mem_additional)
+ {
+ for (int i = 0; i < mem_additional->used_size; ++i)
+ zmem_putbyte (g_codes[g_numberOfInstructions],
+ mem_additional->contents[i]);
+ zmem_destroy (mem_additional);
+ }
+
+ ++g_numberOfInstructions;
+ return len;
+ }
+
+ 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;
+}
+
+#define MAX_LINESIZE 1024
+
+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');
+ }
+
+ fclose (fp);
+ return 0;
+}
+
+/*
+
+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)
+}
+
+
+*/
+
+
+void
+init_parser ()
+{
+ g_numberOfInstructions = 0;
+}
+
+
+void
+relase_parser ()
+{
+ for (int i = 0; i < g_numberOfInstructions; ++i)
+ {
+ zmem_destroy (g_codes[i]);
+ }
+ g_numberOfInstructions = 0;
+}