Added error messages displaying using source file name and line number
[zilutils.git] / zilasm / parser.cpp
index 31e257fd444623db965366e8b293d130f8b79032..b819792a14815b07fa6bc4c866a561df6d699f4f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * parser.c -- part of ZilUtils/ZilAsm
  *
- * Copyright (C) 2016, 2019 Jason Self <j@jxself.org>
+ * Copyright (C) 2016, 2019, 2020 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
 #include <string.h>            /* strlen */
 #include <ctype.h>
 #include <string>
+#include <stack>
 using namespace std;
 
 
 #include "header.h"
 #include "parser.h"
+#include "directives.h"
 
 extern "C"
 {
-#include "directives.h"
 #include "opcodes.h"
 }
 #include "labels.h"
@@ -42,21 +43,45 @@ extern "C"
 #define isbindigit(c)  ((c) == '0' || (c) == '1')
 
 /* !!! TODO !!! */
-#define fatal_error(errmsg) printf(errmsg)
+//#define fatal_error(errmsg) printf(errmsg)
 #define PC NULL
 
-unsigned g_numberOfInstructions = 0;
+unsigned g_number_of_instructions = 0;
+
+unsigned g_currentLineNumber = 0;
+//string g_source_directory;
+bool g_haveErrors = false;
+
+stack<Parsing_Context> g_parsing_contexts;
 
 
 ZMemblock (*g_codes[MAX_NUMBER_OF_INSTRUCTIONS]);
 
+string
+build_error_message(const char *message)
+{
+       char buff[300];
+       sprintf(buff, "error at %s%s line %d: %s", g_parsing_contexts.top().current_directory.c_str(),
+               g_parsing_contexts.top().current_file_name.c_str(), g_currentLineNumber, message);
+       return string(buff);
+}
+
+
+void
+fatal_error(const char *errmsg)
+{
+       printf( "%s\n", errmsg);
+       g_haveErrors = true;
+}
+
+
 
 void
 checksep (const char *p)
 {
   if (!*p || iscomment (*p) || isspace (*p))
     return;
-  fatal_error ("wrong chars");
+  fatal_error (build_error_message ("wrong chars").c_str());
 }
 
 
@@ -91,7 +116,7 @@ tryparse_directive (const char *p)
   Directive_handler f = directive_lookup (a, b - a);
   if (!f)
     return 0;
-  return (*f) (b);
+  return (b-a) + (*f) (b);
 }
 
 
@@ -115,7 +140,7 @@ tryparse_label (const char *a, const char *b, const char *c)
     }
   else
     {
-      fatal_error ("wrong label type");
+      fatal_error (build_error_message("wrong label type").c_str());
     }
 
   while (*c++ == ':');
@@ -144,72 +169,96 @@ tryparse_name (const char *a)
 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)
+       bool display_error = false;
+       int len = 0;
+       const char *b = pass_alnums(a);
+       if (b != a)
        {
-       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;
+               len = b ? b - a : strlen(a);
+               ZOpcode *op = (ZOpcode *)symtable_lookup2(Opcodes, a, len);
+               if (op)
+               {
+                       ZOpcode_flags flags = op->flags;
+                       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:
+                       {
+                               display_error = true;
+                       }
+                       }
+
+
+                       if (display_error == false)
+                       {
+
+                               int instruction_size = 1;
+                               if (mem_additional)
+                                       instruction_size += mem_additional->used_size;
+
+                               g_codes[g_number_of_instructions] = zmem_init(instruction_size);
+                               zmem_putbyte(g_codes[g_number_of_instructions], op->opcode);
+
+                               if (mem_additional)
+                               {
+                                       for (int i = 0; i < mem_additional->used_size; ++i)
+                                               zmem_putbyte(g_codes[g_number_of_instructions],
+                                                       mem_additional->contents[i]);
+                                       zmem_destroy(mem_additional);
+                               }
+
+                               ++g_number_of_instructions;
+                               return len;
+                       }
+               }
+               else
+               {
+                       //display_error = true;
+                       string message = "wrong line \"" + string(a) + string("\"");
+                       fatal_error(build_error_message(message.c_str()).c_str());
+               }
        }
 
-      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)
+       if (display_error)
        {
-         for (int i = 0; i < mem_additional->used_size; ++i)
-           zmem_putbyte (g_codes[g_numberOfInstructions],
-                         mem_additional->contents[i]);
-         zmem_destroy (mem_additional);
+               char buff[300];
+               if (len == 0)
+                       len = strlen(a);
+               char *instrcution_name = (char *)malloc(len + 1);
+               memcpy(instrcution_name, a, len);
+               instrcution_name[len] = 0;
+               string message = "instruction " + string(instrcution_name) + string(" is not supported yet");
+               fatal_error(build_error_message(message.c_str()).c_str());
+               free(instrcution_name);
        }
 
-      ++g_numberOfInstructions;
-      return len;
-    }
-
-  return 0;
+       return strlen(a);
 }
 
 
@@ -233,7 +282,7 @@ parse_line (const char *p)
        return n;               // ..label or assignment
       if (n = tryparse_instruction (p))
        return n;
-      fatal_error ("wrong line");
+      //fatal_error ("wrong line");
     }
   return 0;
 }
@@ -241,32 +290,49 @@ parse_line (const char *p)
 #define MAX_LINESIZE 1024
 
 int
-parse_file (const char *filename)
+parse_file (/*const char *filename*/)
 {
-  FILE *fp = fopen (filename, "r");
-  if (!fp)
-    fatal_error ("wrong file");
+       if (g_parsing_contexts.size() > 0)
+       {
+               string filename = g_parsing_contexts.top().current_directory + g_parsing_contexts.top().current_file_name;
 
-  //const int MAX_LINESIZE = 1024;
-  char line[MAX_LINESIZE];
-  int newline_missing = 0;
+               FILE *fp = fopen(filename.c_str(), "r");
+               if (fp)
+               {
 
-  while (fgets (line, MAX_LINESIZE, fp))
-    {
-      if (newline_missing)
-       fatal_error ("line too long");
+                       g_currentLineNumber = 0;
 
-      int n = strlen (line);
-      if (!n)
-       continue;
+                       //const int MAX_LINESIZE = 1024;
+                       char line[MAX_LINESIZE];
+                       int newline_missing = 0;
 
-      parse_line (line);
+                       while (g_stopParsing == 0 && fgets(line, MAX_LINESIZE, fp))
+                       {
+                               ++g_currentLineNumber;
 
-      newline_missing = (line[n - 1] != '\n');
-    }
+                               if (newline_missing)
+                                       fatal_error(build_error_message("line too long").c_str());
 
-  fclose (fp);
-  return 0;
+                               int n = strlen(line);
+                               if (!n)
+                                       continue;
+
+                               parse_line(line);
+
+                               newline_missing = (line[n - 1] != '\n');
+                       }
+
+                       fclose(fp);
+               }
+               else
+               {
+                       string message = string("can't open file ") + filename;
+                       fatal_error(message.c_str());
+               }
+
+               g_parsing_contexts.pop();
+       }
+       return 0;
 }
 
 /*
@@ -298,16 +364,19 @@ if (current_token == DIRECTIVE) {
 void
 init_parser ()
 {
-  g_numberOfInstructions = 0;
+  g_number_of_instructions = 0;
 }
 
 
+
+
+
 void
 relase_parser ()
 {
-  for (int i = 0; i < g_numberOfInstructions; ++i)
+  for (int i = 0; i < g_number_of_instructions; ++i)
     {
       zmem_destroy (g_codes[i]);
     }
-  g_numberOfInstructions = 0;
+  g_number_of_instructions = 0;
 }