From 633e24778bccbc5f035bdb8516e8cc75c85123d9 Mon Sep 17 00:00:00 2001 From: Jason Self Date: Sun, 23 Aug 2020 08:36:28 -0700 Subject: [PATCH] Added error messages displaying using source file name and line number Added .END and .INSERT directives --- zilasm/Makefile.am | 4 +- zilasm/{directives.c => directives.cpp} | 78 +++++++- zilasm/directives.h | 4 +- zilasm/main.cpp | 44 ++++- zilasm/parser.cpp | 249 +++++++++++++++--------- zilasm/parser.h | 16 +- zilasm/string_table.cpp | 20 +- 7 files changed, 301 insertions(+), 114 deletions(-) rename zilasm/{directives.c => directives.cpp} (72%) diff --git a/zilasm/Makefile.am b/zilasm/Makefile.am index 5faa8ef..06a834b 100644 --- a/zilasm/Makefile.am +++ b/zilasm/Makefile.am @@ -2,7 +2,7 @@ # Process this file with automake to produce Makefile.in. # # Copyright (C) 2015 Alexander Andrejevic -# Copyright (C) 2019 Jason Self +# Copyright (C) 2019, 2020 Jason Self # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -21,5 +21,5 @@ bin_PROGRAMS = zilasm man_MANS = zilasm.1 -zilasm_SOURCES = main.cpp opcodes.c symtable.c header.cpp parser.cpp directives.c labels.cpp string_table.cpp zmem.c +zilasm_SOURCES = main.cpp opcodes.c symtable.c header.cpp parser.cpp directives.cpp labels.cpp string_table.cpp zmem.c include_HEADERS = opcodes.h symtable.h header.h parser.h directives.h labels.h string_table.h zmem.h diff --git a/zilasm/directives.c b/zilasm/directives.cpp similarity index 72% rename from zilasm/directives.c rename to zilasm/directives.cpp index 7c4eb19..d15ba89 100644 --- a/zilasm/directives.c +++ b/zilasm/directives.cpp @@ -1,7 +1,7 @@ /* * directives.c -- part of ZilUtils/ZilAsm * - * Copyright (C) 2016 Jason Self + * Copyright (C) 2016, 2020 Jason Self * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -21,11 +21,22 @@ #include /* bsearch */ #include /* strcmp */ +#include +#include +#include +using namespace std; +#include "header.h" +#include "parser.h" #include "directives.h" #define ARRAY_SIZE(x) ((sizeof(x)) / (sizeof(x[0]))) +int g_stopParsing = 0; +stack g_fileHandlers; + + + static int byte_handler (const char *args) { @@ -36,8 +47,8 @@ byte_handler (const char *args) static int end_handler (const char *args) { - /* !!! TODO !!! */ - return 0; + g_stopParsing = 1; + return 0; } static int @@ -85,8 +96,61 @@ gvar_handler (const char *args) static int insert_handler (const char *args) { - /* !!! TODO !!! */ - return 0; + string file_name; + char *p = (char*)args; + while (*p == ' ') p++; + + if (*p == '"') + { + p++; + do + { + file_name += *p; + p++; + } + while (*p != '"' && *p != 0 ) ; + } + else + { + do + { + file_name += *p; + p++; + } while (*p != ' ' && *p != '\n' && *p != '\r' && *p != '\t' && *p != 0); + } + + if (file_name.find('.') == string::npos) + { + file_name += ".zap"; + } + +#ifdef WIN32 + char delimeter = '\\'; +#else + char delimeter = '/'; +#endif + + Parsing_Context pc; + if (file_name.rfind(delimeter) == string::npos) + { + pc.current_directory = ""; + pc.current_file_name = file_name; + } + else + { + pc.current_directory = file_name.substr(0, file_name.rfind(delimeter)+1); + pc.current_file_name = file_name.substr(file_name.rfind(delimeter)+1); + } + + pc.current_directory = g_parsing_contexts.top().current_directory + pc.current_directory; + //pc.current_file_name = s; + g_parsing_contexts.push(pc); + + + unsigned saveLineNumber = g_currentLineNumber; + parse_file(); //s.c_str()); + g_currentLineNumber = saveLineNumber; + return strlen(args); } static int @@ -97,7 +161,7 @@ len_handler (const char *args) } static int -new_handler (const char *args) +newdirective_handler (const char *args) { /* !!! TODO !!! */ return 0; @@ -178,7 +242,7 @@ static Directive Directives[] = { "GVAR", gvar_handler, "INSERT", insert_handler, "LEN", len_handler, - "NEW", new_handler, + "NEW", newdirective_handler, "OBJECT", object_handler, "PROP", prop_handler, "STR", str_handler, diff --git a/zilasm/directives.h b/zilasm/directives.h index 5988c0a..b1ddd23 100644 --- a/zilasm/directives.h +++ b/zilasm/directives.h @@ -1,7 +1,7 @@ /* * directives.h -- part of ZilUtils/ZilAsm * - * Copyright (C) 2016 Jason Self + * Copyright (C) 2016, 2020 Jason Self * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -31,5 +31,7 @@ typedef struct } Directive; Directive_handler directive_lookup (const char *name, unsigned namelen); +extern int g_stopParsing; +extern stack g_fileHandlers; #endif /* ifndef ZILASM_DIRECTIVES */ diff --git a/zilasm/main.cpp b/zilasm/main.cpp index 22b7e71..68846b0 100644 --- a/zilasm/main.cpp +++ b/zilasm/main.cpp @@ -2,7 +2,7 @@ * main.c * * Copyright (C) 2015 Alexander Andrejevic - * Copyright (C) 2015, 2019 Jason Self + * Copyright (C) 2015, 2019, 2020 Jason Self * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -24,6 +24,12 @@ #include #include #include +#include +#include +#include +using namespace std; + + extern "C" { #include @@ -39,9 +45,7 @@ extern "C" } #include "parser.h" -#include -#include -using namespace std; + const int DEFAULT_ZVERSION = 6; @@ -143,7 +147,7 @@ CMain::assembly () ++m_code_size; // write instructions' codes - for (int i = 0; i < g_numberOfInstructions; ++i) + for (int i = 0; i < g_number_of_instructions; ++i) { for (int j = 0; j < g_codes[i]->used_size; ++j) { @@ -424,9 +428,33 @@ main (int argc, char *argv[], char *envp[]) init_parser (); - for (int i = optind; i < argc; i++) - parse_file (argv[i]); - main.assembly (); + //for (int i = optind; i < argc; i++) + // parse_file(argv[i]); + + string file_name = argv[optind]; + Parsing_Context pc; + +#ifdef WIN32 + char delimeter = '\\'; +#else + char delimeter = '/'; +#endif + + if (file_name.rfind(delimeter) == string::npos) + { + pc.current_directory = ""; + pc.current_file_name = file_name; + } + else + { + pc.current_directory = file_name.substr(0, file_name.rfind(delimeter)+1); + pc.current_file_name = file_name.substr(file_name.rfind(delimeter)+1); + } + g_parsing_contexts.push(pc); + + parse_file();// argv[optind]); + if ( !g_haveErrors ) + main.assembly (); /* TODO! List global symbols */ /* TODO! Find abbreviations */ diff --git a/zilasm/parser.cpp b/zilasm/parser.cpp index 31e257f..b819792 100644 --- a/zilasm/parser.cpp +++ b/zilasm/parser.cpp @@ -1,7 +1,7 @@ /* * parser.c -- part of ZilUtils/ZilAsm * - * Copyright (C) 2016, 2019 Jason Self + * Copyright (C) 2016, 2019, 2020 Jason Self * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -23,15 +23,16 @@ #include /* strlen */ #include #include +#include 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 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; } diff --git a/zilasm/parser.h b/zilasm/parser.h index 2ed9ae7..007d2ff 100644 --- a/zilasm/parser.h +++ b/zilasm/parser.h @@ -1,7 +1,7 @@ /* * parser.h -- part of ZilUtils/ZilAsm * - * Copyright (C) 2016, 2019 Jason Self + * Copyright (C) 2016, 2019, 2020 Jason Self * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -31,11 +31,21 @@ struct Instruction void init_parser (); -int parse_file (const char *filename); +int parse_file();// const char *filename); -extern unsigned g_numberOfInstructions; +extern unsigned g_number_of_instructions; #define MAX_NUMBER_OF_INSTRUCTIONS 65536 extern ZMemblock (*g_codes[MAX_NUMBER_OF_INSTRUCTIONS]); +struct Parsing_Context +{ + string current_directory; + string current_file_name; +}; + +extern stack g_parsing_contexts; +extern unsigned g_currentLineNumber; +extern bool g_haveErrors; + #endif /* ifndef ZILASM_PARSER */ diff --git a/zilasm/string_table.cpp b/zilasm/string_table.cpp index a086b87..ed2b6d7 100644 --- a/zilasm/string_table.cpp +++ b/zilasm/string_table.cpp @@ -1,7 +1,7 @@ /* * string_table.cpp -- part of ZilUtils/ZilAsm * - * Copyright (C) 2019 Jason Self + * Copyright (C) 2019, 2020 Jason Self * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -90,7 +90,14 @@ String_table::encrypt_string (const char *str, ZMemblock * zmb) } else if (c == ' ') { - write_one_word_to_string_table (zmb, &w, &numberOfSymbolsInWord, 0); + //if (numberOfSymbolsInWord != 0) + //{ + // zmem_putbyte(zmb, (w >> 8) & 255); + // zmem_putbyte(zmb, w & 255); + // numberOfSymbolsInWord = 0; + // w = 0; + //} + write_one_word_to_string_table (zmb, &w, &numberOfSymbolsInWord, 0); } else { @@ -130,7 +137,14 @@ String_table::encrypt_string (const char *str, ZMemblock * zmb) numberOfSymbolsInWord = 0; w = 0; } - zmb->contents[zmb->used_size - 2] |= 0x80; + + if ((zmb->contents[zmb->used_size - 1] & 31) == 0) // if the last symbol is a space or not filled + zmb->contents[zmb->used_size - 2] |= 0x80; // then we mark this word as the last word + else + { + zmem_putbyte(zmb, 0x80); // otherwise we add one more empty word + zmem_putbyte(zmb, 0x0); // with 15-th bit set + } return zmb; } -- 2.31.1