Updating to reflect the latest work
[zilutils.git] / zilasm / parser.cpp
diff --git a/zilasm/parser.cpp b/zilasm/parser.cpp
new file mode 100644 (file)
index 0000000..31e257f
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ * 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;
+}