From b1f151e1500e1fdadafaab6b13df6e0a8f32136e Mon Sep 17 00:00:00 2001 From: Jason Self Date: Sun, 23 Aug 2020 08:43:45 -0700 Subject: [PATCH] Added ability to define multiple functions (without parameters) and call them --- zilasm/Makefile.am | 2 +- zilasm/compiler.cpp | 138 ++++++++++++++++ zilasm/compiler.h | 73 +++++++++ zilasm/directives.cpp | 119 +++++++------- zilasm/directives.h | 18 ++- zilasm/header.cpp | 14 +- zilasm/header.h | 6 +- zilasm/include_all.h | 76 +++++++++ zilasm/main.cpp | 242 +++++++--------------------- zilasm/opcodes.c | 4 +- zilasm/opcodes.h | 7 +- zilasm/parser.cpp | 348 ++++++++++++++++++++++++++++------------ zilasm/parser.h | 72 ++++++++- zilasm/string_table.cpp | 7 - 14 files changed, 753 insertions(+), 373 deletions(-) create mode 100644 zilasm/compiler.cpp create mode 100644 zilasm/compiler.h create mode 100644 zilasm/include_all.h diff --git a/zilasm/Makefile.am b/zilasm/Makefile.am index 06a834b..78f5d37 100644 --- a/zilasm/Makefile.am +++ b/zilasm/Makefile.am @@ -21,5 +21,5 @@ bin_PROGRAMS = zilasm man_MANS = zilasm.1 -zilasm_SOURCES = main.cpp opcodes.c symtable.c header.cpp parser.cpp directives.cpp labels.cpp string_table.cpp zmem.c +zilasm_SOURCES = main.cpp compiler.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/compiler.cpp b/zilasm/compiler.cpp new file mode 100644 index 0000000..eaa2317 --- /dev/null +++ b/zilasm/compiler.cpp @@ -0,0 +1,138 @@ +/* +* parser.c -- part of ZilUtils/ZilAsm +* +* Copyright (C) 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 +* 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 +* +* SPDX-License-Identifier: AGPL-3.0-or-later +*/ + +#include "include_all.h" + +CCompiler::CCompiler() :m_output_file(NULL) +{ +} + +int +CCompiler::assembly() +{ + FILE *file = fopen(m_output_file, "wb"); + if (file) + { + program_header_reset(6); + int size = sizeof(program_header); + + program_header.mode = 0; + program_header.release = 1; // game version + + m_code_size = 0; + ZMemblock *zmem_code = zmem_init(65536); + + unsigned current_address = 64; + + if (parser.m_functions.size() > 0) + { + //unsigned function_table_size = parser.m_functions.size() * 2; + program_header.H_FUNCTIONS_OFFSET = current_address >> 3; + //current_address += function_table_size; + } + else + program_header.H_FUNCTIONS_OFFSET = 0; + + int code_start_offset = current_address; + + if (parser.m_start_function_name == "") + program_header.startPC = code_start_offset >> 2; + else + program_header.startPC = parser.m_functions.find(parser.m_start_function_name)->second.address >> 2; + + // write instructions' codes + m_code_size = parser.output_codes(zmem_code); + + if (m_code_size & 7) + { + const int additional_mem = 8 - (m_code_size & 7); + for (int i = 0; i < additional_mem; ++i) + zmem_putbyte(zmem_code, 0); + m_code_size += additional_mem; + } + + program_header.dynamic_size = 8; + + //Program_header.h_file_size = 33; //sizeof(Program_header) + zmb->used_size; + + //m_code_size = 8; + + Word stringTableOffset = m_code_size; + program_header.H_STRINGS_OFFSET = (64 + stringTableOffset) >> 3; + + int stringTableSize = 64; + program_header.h_file_size = + (code_start_offset + m_code_size + stringTableSize) >> 3; + ZMemblock *zmb = zmem_init(program_header.h_file_size * 8); + + for (int i = 0; i < m_code_size; ++i) + zmem_putbyte(zmb, zmem_code->contents[i]); + + zmem_destroy(zmem_code); + + //zmem_putbyte(zmb, 0); // number of local variables + //zmem_putbyte(zmb, 141); // print addr command + + //Word offset = 0; + //zmem_putbyte(zmb, (offset >> 8) & 255); + //zmem_putbyte(zmb, offset & 255); + + //zmem_putbyte(zmb, 186); // quit command + + // output zeros until string table begins + while (zmb->used_size < stringTableOffset) + zmem_putbyte(zmb, 0); + // + //// fill string table with one string + //add_string_to_string_table("Hello, World!", zmb); + + outputToFile(&program_header, file); + //output_function_table(file); + + fwrite(zmb->contents, zmb->allocated_size, 1, file); + fclose(file); + } + + return OK; +} + + +char * +CCompiler::get_output_file_name() +{ + return m_output_file; +} + + +void +CCompiler::output_function_table(FILE *file) +{ + if (parser.m_functions.size()) + { + for(map::iterator iter = parser.m_functions.begin(); iter != parser.m_functions.end(); ++iter) + { + Word w = (iter->second.address) >> 4; + fprintf ( file, "%c", (w >> 8) & 255); + fprintf(file, "%c", w & 255); + } + + } +} \ No newline at end of file diff --git a/zilasm/compiler.h b/zilasm/compiler.h new file mode 100644 index 0000000..a885819 --- /dev/null +++ b/zilasm/compiler.h @@ -0,0 +1,73 @@ +/* + * compiler.h -- part of ZilUtils/ZilAsm + * + * Copyright (C) 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 + * 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 + * + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +#ifndef ZILASM_COMPILER +#define ZILASM_COMPILER + + +typedef struct +{ + int todo; +} Opcode_dict; + + + +struct String_Table_Elem +{ + string value; // value in ASCII format + int index; +}; + + +class CCompiler +{ +public: + CCompiler(); + int assembly(); + void fill_config(void); + void get_arguments(int argc, char *argv[], char *envp[]); + char *get_output_file_name(); + CParser parser; + +private: + char *m_output_file; + list < String_Table_Elem > m_string_table; + int m_code_size; + + char *build_output_filename(const char basename[], const char *suffix); + void fill_zserial(void); + void new_file_suffix(char *result, size_t maxlen, const char *src, + const char *newsuffix); + void output_code_section(); + void output_function_table(FILE *file); + void parse_intarg(int *dest, const char name[], int min, int max, + int defval); + void parse_zserial(void); + void print_usage(int failed); + void print_version(); + void wrong_arg(const char *err, ...); +}; + +enum +{ + FAIL = -1, OK = 0, NEED_RESTART = 1 +}; + +#endif diff --git a/zilasm/directives.cpp b/zilasm/directives.cpp index d15ba89..94c39f9 100644 --- a/zilasm/directives.cpp +++ b/zilasm/directives.cpp @@ -19,16 +19,7 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ -#include /* bsearch */ -#include /* strcmp */ -#include -#include -#include -using namespace std; - -#include "header.h" -#include "parser.h" -#include "directives.h" +#include "include_all.h" #define ARRAY_SIZE(x) ((sizeof(x)) / (sizeof(x[0]))) @@ -38,63 +29,65 @@ stack g_fileHandlers; static int -byte_handler (const char *args) +byte_handler (const char *args, CParser* parser) { /* !!! TODO !!! */ return 0; } static int -end_handler (const char *args) +end_handler (const char *args, CParser* parser) { g_stopParsing = 1; return 0; } static int -endi_handler (const char *args) +endi_handler (const char *args, CParser* parser) { /* !!! TODO !!! */ return 0; } static int -endt_handler (const char *args) +endt_handler (const char *args, CParser* parser) { /* !!! TODO !!! */ return 0; } static int -fstr_handler (const char *args) +fstr_handler (const char *args, CParser* parser) { /* !!! TODO !!! */ return 0; } static int -funct_handler (const char *args) +funct_handler (const char *args, CParser* parser) { /* !!! TODO !!! */ - return 0; + + parser->add_function(args); + return 0; } static int -gstr_handler (const char *args) +gstr_handler (const char *args, CParser* parser) { /* !!! TODO !!! */ return 0; } static int -gvar_handler (const char *args) +gvar_handler (const char *args, CParser* parser) { /* !!! TODO !!! */ return 0; } static int -insert_handler (const char *args) +insert_handler (const char *args, CParser* parser) { string file_name; char *p = (char*)args; @@ -146,113 +139,90 @@ insert_handler (const char *args) //pc.current_file_name = s; g_parsing_contexts.push(pc); - - unsigned saveLineNumber = g_currentLineNumber; - parse_file(); //s.c_str()); - g_currentLineNumber = saveLineNumber; + unsigned saveLineNumber = parser->m_current_line_number; + parser->parse_file(); //s.c_str()); + parser->m_current_line_number = saveLineNumber; return strlen(args); } static int -len_handler (const char *args) +len_handler (const char *args, CParser* parser) { /* !!! TODO !!! */ return 0; } static int -newdirective_handler (const char *args) +newdirective_handler (const char *args, CParser* parser) { /* !!! TODO !!! */ return 0; } static int -object_handler (const char *args) +object_handler (const char *args, CParser* parser) { /* !!! TODO !!! */ return 0; } static int -prop_handler (const char *args) +prop_handler (const char *args, CParser* parser) { /* !!! TODO !!! */ return 0; } static int -str_handler (const char *args) +str_handler (const char *args, CParser* parser) { /* !!! TODO !!! */ return 0; } static int -strl_handler (const char *args) +strl_handler (const char *args, CParser* parser) { /* !!! TODO !!! */ return 0; } static int -table_handler (const char *args) +table_handler (const char *args, CParser* parser) { /* !!! TODO !!! */ return 0; } static int -vocbeg_handler (const char *args) +vocbeg_handler (const char *args, CParser* parser) { /* !!! TODO !!! */ return 0; } static int -vocend_handler (const char *args) +vocend_handler (const char *args, CParser* parser) { /* !!! TODO !!! */ return 0; } static int -word_handler (const char *args) +word_handler (const char *args, CParser* parser) { /* !!! TODO !!! */ return 0; } static int -zword_handler (const char *args) +zword_handler (const char *args, CParser* parser) { /* !!! TODO !!! */ return 0; } -// Sorted array -static Directive Directives[] = { - "BYTE", byte_handler, - "END", end_handler, - "ENDI", endi_handler, - "ENDT", endt_handler, - "FSTR", fstr_handler, - "FUNCT", funct_handler, - "GSTR", gstr_handler, - "GVAR", gvar_handler, - "INSERT", insert_handler, - "LEN", len_handler, - "NEW", newdirective_handler, - "OBJECT", object_handler, - "PROP", prop_handler, - "STR", str_handler, - "STRL", strl_handler, - "TABLE", table_handler, - "VOCBEG", vocbeg_handler, - "VOCEND", vocend_handler, - "WORD", word_handler, - "ZWORD", zword_handler -}; + typedef struct { @@ -274,11 +244,40 @@ namecmp (const void *key, const void *elem) } Directive_handler -directive_lookup (const char *name, unsigned namelen) +CDirectives::directive_lookup (const char *name, unsigned namelen) { - Name n = { name, namelen }; + // Sorted array + static Directive Directives[] = { + "BYTE", byte_handler, + "END", end_handler, + "ENDI", endi_handler, + "ENDT", endt_handler, + "FSTR", fstr_handler, + "FUNCT", funct_handler, + "GSTR", gstr_handler, + "GVAR", gvar_handler, + "INSERT", insert_handler, + "LEN", len_handler, + "NEW", newdirective_handler, + "OBJECT", object_handler, + "PROP", prop_handler, + "STR", str_handler, + "STRL", strl_handler, + "TABLE", table_handler, + "VOCBEG", vocbeg_handler, + "VOCEND", vocend_handler, + "WORD", word_handler, + "ZWORD", zword_handler + }; + + Name n = { name, namelen }; Directive *p = (Directive *) bsearch (&n, Directives, ARRAY_SIZE (Directives), sizeof (Directive), namecmp); return p ? p->handler : NULL; } + + +CDirectives::CDirectives(CParser *parser) :m_parser(parser) +{ +} \ No newline at end of file diff --git a/zilasm/directives.h b/zilasm/directives.h index b1ddd23..9f66060 100644 --- a/zilasm/directives.h +++ b/zilasm/directives.h @@ -22,7 +22,9 @@ #ifndef ZILASM_DIRECTIVES #define ZILASM_DIRECTIVES 1 -typedef int (*Directive_handler) (const char *directive_args); +class CParser; + +typedef int (*Directive_handler) (const char *directive_args, CParser* parser); typedef struct { @@ -30,8 +32,20 @@ typedef struct Directive_handler handler; } Directive; -Directive_handler directive_lookup (const char *name, unsigned namelen); extern int g_stopParsing; extern stack g_fileHandlers; + +class CDirectives +{ +public: + CDirectives(CParser *parser); + Directive_handler directive_lookup(const char *name, unsigned namelen); + +private: + CParser *m_parser; + + CDirectives(); + //int insert_handler(const char *args); +}; #endif /* ifndef ZILASM_DIRECTIVES */ diff --git a/zilasm/header.cpp b/zilasm/header.cpp index 863c65e..c643eeb 100644 --- a/zilasm/header.cpp +++ b/zilasm/header.cpp @@ -1,7 +1,7 @@ /* * header.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 @@ -25,22 +25,22 @@ #include "header.h" -Program_header_struct Program_header; +Program_header_struct program_header; const unsigned MAX_HEADER_LEN = 40; void program_header_reset (unsigned zversion) { - bzero (&Program_header, sizeof (Program_header)); - Program_header.version = zversion; + bzero (&program_header, sizeof (program_header)); + program_header.version = zversion; } ZMemblock * program_header_build (void) { ZMemblock *zmb = zmem_init (MAX_HEADER_LEN); - zmem_putbyte (zmb, Program_header.version); + zmem_putbyte (zmb, program_header.version); /* TODO */ return zmb; } @@ -61,7 +61,9 @@ outputToFile (Program_header_struct * pHeader, FILE * file) h.startPC = swapBytes (h.startPC); h.h_file_size = swapBytes (h.h_file_size); - h.H_STRINGS_OFFSET = swapBytes (h.H_STRINGS_OFFSET); + h.H_STRINGS_OFFSET = swapBytes(h.H_STRINGS_OFFSET); + + h.H_FUNCTIONS_OFFSET = swapBytes(h.H_FUNCTIONS_OFFSET); int size = sizeof (Program_header_struct); fwrite (&h, sizeof (Program_header_struct), 1, file); diff --git a/zilasm/header.h b/zilasm/header.h index c63e665..5607b3a 100644 --- a/zilasm/header.h +++ b/zilasm/header.h @@ -1,7 +1,7 @@ /* * header.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 @@ -140,7 +140,7 @@ typedef struct } Program_header_struct; -extern Program_header_struct Program_header; +extern Program_header_struct program_header; void program_header_reset (unsigned zversion); ZMemblock *program_header_build (void); @@ -157,5 +157,5 @@ typedef struct void outputToFile (Program_header_struct * h, FILE * file); -void relase_parser (); +//void relase_parser (); #endif /* ifndef ZILASM_HEADER */ diff --git a/zilasm/include_all.h b/zilasm/include_all.h new file mode 100644 index 0000000..66e0c06 --- /dev/null +++ b/zilasm/include_all.h @@ -0,0 +1,76 @@ +/* + * include_all.h -- part of ZilUtils/ZilAsm + * + * Copyright (C) 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 + * 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 + * + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#pragma once + +#ifndef INCLUDE_ALL +#define INCLUDE_ALL + + +//#include +//#include +//#include +//#include + + +#include +#include /* fopen, fgets */ +#include +#include /* strlen */ +extern "C" +{ +#include +} +#include +#include +#include + + +#include +#include +#include +#include +#include +using namespace std; + + + +#include "config.h" +#include "header.h" +extern "C" +{ +#include "opcodes.h" +} + +#include "header.h" +#include "directives.h" +#include "parser.h" + + +//extern "C" +//{ +//#include "opcodes.h" +//} +#include "labels.h" +#include "string_table.h" +#include "compiler.h" +#endif + diff --git a/zilasm/main.cpp b/zilasm/main.cpp index 68846b0..e7bd734 100644 --- a/zilasm/main.cpp +++ b/zilasm/main.cpp @@ -19,41 +19,45 @@ * * SPDX-License-Identifier: AGPL-3.0-or-later */ - -#include -#include -#include -#include -#include -#include -#include -using namespace std; - - -extern "C" -{ -#include -} -#include -#include -#include -#include "config.h" -#include "header.h" -extern "C" -{ -#include "opcodes.h" -} -#include "parser.h" - - +// +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//using namespace std; +// +// +//extern "C" +//{ +//#include +//} +//#include +//#include +//#include +//#include "config.h" +//#include "header.h" +//extern "C" +//{ +//#include "opcodes.h" +//} +//#include "directives.h" +//#include "parser.h" +//#include "compiler.h" + + +#include "include_all.h" const int DEFAULT_ZVERSION = 6; enum { ZVERSION = 11, ZORKID, ZSERIAL }; -enum -{ FAIL = -1, OK = 0, NEED_RESTART = 1 }; + static struct option const long_options[] = { {"help", no_argument, NULL, 'h'}, @@ -66,152 +70,24 @@ static struct option const long_options[] = { }; -typedef struct -{ - int todo; -} Opcode_dict; -struct -{ - int zversion; /* 0 - 8 */ - int zorkid; /* 0 - 65535 */ - char zserial[7]; /* YYMMDD */ - Opcode_dict *opcode_dict; -} Config; -struct String_Table_Elem -{ - string value; // value in ASCII format - int index; -}; -class CMain -{ -public: - CMain (); - int assembly (); - void fill_config (void); - void get_arguments (int argc, char *argv[], char *envp[]); - - char *get_output_file_name (); -private: - char *m_output_file; - list < String_Table_Elem > m_string_table; - int m_code_size; - - - char *build_output_filename (const char basename[], const char *suffix); - void fill_zserial (void); - void new_file_suffix (char *result, size_t maxlen, const char *src, - const char *newsuffix); - - void output_code_section (); - - void parse_intarg (int *dest, const char name[], int min, int max, - int defval); - void parse_zserial (void); - void print_usage (int failed); - void print_version (); - void wrong_arg (const char *err, ...); - -}; - - -CMain::CMain ():m_output_file (NULL) -{ -} - -int -CMain::assembly () -{ - FILE *file = fopen (m_output_file, "wb"); - if (file) - { - program_header_reset (6); - int size = sizeof (Program_header); - Program_header.mode = 0; - Program_header.release = 1; // game version - int code_start_offset = 64; - Program_header.startPC = code_start_offset >> 2; - - m_code_size = 0; - ZMemblock *zmem_code = zmem_init (65536); - - /// write zero number of local variables - zmem_putbyte (zmem_code, 0); // number of local variables - ++m_code_size; - - // write instructions' codes - for (int i = 0; i < g_number_of_instructions; ++i) - { - for (int j = 0; j < g_codes[i]->used_size; ++j) - { - zmem_putbyte (zmem_code, g_codes[i]->contents[j]); - ++m_code_size; - } - } - - if (m_code_size & 7) - m_code_size += 8 - (m_code_size & 7); - - Program_header.dynamic_size = 8; - - //Program_header.h_file_size = 33; //sizeof(Program_header) + zmb->used_size; - - //m_code_size = 8; - - Word stringTableOffset = m_code_size; - Program_header.H_STRINGS_OFFSET = (64 + stringTableOffset) >> 3; - - int stringTableSize = 64; - Program_header.h_file_size = - (code_start_offset + m_code_size + stringTableSize) >> 3; - ZMemblock *zmb = zmem_init (Program_header.h_file_size * 8); - - for (int i = 0; i < m_code_size; ++i) - zmem_putbyte (zmb, zmem_code->contents[i]); - - zmem_destroy (zmem_code); - - //zmem_putbyte(zmb, 0); // number of local variables - //zmem_putbyte(zmb, 141); // print addr command - - //Word offset = 0; - //zmem_putbyte(zmb, (offset >> 8) & 255); - //zmem_putbyte(zmb, offset & 255); - - //zmem_putbyte(zmb, 186); // quit command - - // output zeros until string table begins - while (zmb->used_size < stringTableOffset) - zmem_putbyte (zmb, 0); - // - //// fill string table with one string - //add_string_to_string_table("Hello, World!", zmb); - - outputToFile (&Program_header, file); - fwrite (zmb->contents, zmb->allocated_size, 1, file); - fclose (file); - } - - return OK; -} - - -char * -CMain::get_output_file_name () +struct { - return m_output_file; -} - + int zversion; /* 0 - 8 */ + int zorkid; /* 0 - 65535 */ + char zserial[7]; /* YYMMDD */ + Opcode_dict *opcode_dict; +} Config; void -CMain::get_arguments (int argc, char *argv[], char *envp[]) +CCompiler::get_arguments (int argc, char *argv[], char *envp[]) { int opt = 0; while ((opt = getopt_long (argc, argv, "hVo:", long_options, NULL)) != -1) @@ -265,7 +141,7 @@ CMain::get_arguments (int argc, char *argv[], char *envp[]) void -CMain::wrong_arg (const char *err, ...) +CCompiler::wrong_arg (const char *err, ...) { if (err) { @@ -280,7 +156,7 @@ CMain::wrong_arg (const char *err, ...) void -CMain::print_version () +CCompiler::print_version () { printf (PACKAGE_STRING "\n" "License AGPLv3+: GNU AGPL version 3 or later\n" @@ -292,7 +168,7 @@ CMain::print_version () void -CMain::print_usage (int failed) +CCompiler::print_usage (int failed) { printf ("Usage: " PACKAGE_NAME " [OPTION...] [FILES...]\n" "\n" @@ -308,7 +184,7 @@ CMain::print_usage (int failed) } void -CMain::fill_zserial (void) +CCompiler::fill_zserial (void) { time_t t; struct tm *timeinfo; @@ -319,7 +195,7 @@ CMain::fill_zserial (void) void -CMain::fill_config (void) +CCompiler::fill_config (void) { bzero (&Config, sizeof (Config)); Config.zversion = DEFAULT_ZVERSION; @@ -328,7 +204,7 @@ CMain::fill_config (void) void -CMain::parse_intarg (int *dest, const char name[], int min, int max, +CCompiler::parse_intarg (int *dest, const char name[], int min, int max, int defval) { if (!optarg) @@ -348,7 +224,7 @@ CMain::parse_intarg (int *dest, const char name[], int min, int max, void -CMain::parse_zserial (void) +CCompiler::parse_zserial (void) { if (!optarg) { @@ -372,7 +248,7 @@ CMain::parse_zserial (void) void -CMain::new_file_suffix (char *result, size_t maxlen, const char *src, +CCompiler::new_file_suffix (char *result, size_t maxlen, const char *src, const char *newsuffix) { strncpy (result, src, maxlen); @@ -392,7 +268,7 @@ CMain::new_file_suffix (char *result, size_t maxlen, const char *src, char * -CMain::build_output_filename (const char basename[], const char *suffix) +CCompiler::build_output_filename (const char basename[], const char *suffix) { int n = strlen (basename) + strlen (suffix); char *ofile = (char *) malloc (n + 1); /* todo!!! check for NULL. free. */ @@ -410,24 +286,22 @@ init_assembly (void) void -CMain::output_code_section () +CCompiler::output_code_section () { } - int main (int argc, char *argv[], char *envp[]) { - CMain main; + CCompiler compiler; - main.fill_config (); - main.get_arguments (argc, argv, envp); + compiler.fill_config (); + compiler.get_arguments (argc, argv, envp); init_opcodes (Config.zversion, 0); - init_parser (); - + //for (int i = optind; i < argc; i++) // parse_file(argv[i]); @@ -452,12 +326,12 @@ main (int argc, char *argv[], char *envp[]) } g_parsing_contexts.push(pc); - parse_file();// argv[optind]); - if ( !g_haveErrors ) - main.assembly (); + compiler.parser.parse_file();// argv[optind]); + if ( !compiler.parser.have_errors()) + compiler.assembly (); /* TODO! List global symbols */ /* TODO! Find abbreviations */ - relase_parser (); + //relase_parser (); return 0; } diff --git a/zilasm/opcodes.c b/zilasm/opcodes.c index f848e0e..b85b0da 100644 --- a/zilasm/opcodes.c +++ b/zilasm/opcodes.c @@ -1,7 +1,7 @@ /* * opcodes.c -- part of ZilUtils/ZilAsm * - * Copyright (C) 2016, 2019 Jason Self + * Copyright (C) 2016, 2019, 2020 Jason Self * * Based on ZILF (c) 2010, 2015 Jesse McGrew * @@ -140,7 +140,7 @@ static Opcode_detailed_info detailed_opcodes[] = { {177, "RFALSE", "rfalse", 1, 6, Zop_term}, // Rfalse {184, "RSTACK", "ret_popped", 1, 6, Zop_term}, // Rstack // { 268, "RTIME", "RTIME", 5, 6, Zop_store }, // Rtime - {176, "RTRUE", "rtrue", 1, 6, Zop_term}, // Rtrue + {Opcode_RTRUE, "RTRUE", "rtrue", 1, 6, Zop_term}, // Rtrue {181, "SAVE", "save", 1, 3, Zop_branch}, // Save_v1 {181, "SAVE", "save", 4, 4, Zop_store}, // Save_v4 {256, "SAVE", "save", 5, 6, Zop_store}, // Save_V5 diff --git a/zilasm/opcodes.h b/zilasm/opcodes.h index 53e3509..95a0f4f 100644 --- a/zilasm/opcodes.h +++ b/zilasm/opcodes.h @@ -1,7 +1,7 @@ /* * opcodes.h -- part of ZilUtils/ZilAsm * - * Copyright (C) 2016, 2019 Jason Self + * Copyright (C) 2016, 2019, 2020 Jason Self * * Based on ZILF (c) 2010, 2015 Jesse McGrew * @@ -56,11 +56,14 @@ enum Opcodes Opcode_ASHIFT = 259, Opcode_ASSIGNED = 255, Opcode_BAND = 9, + Opcode_CRLF = 187, + Opcode_ICALL1 = 143, + Opcode_ICALL2 = 26, Opcode_PRINT = 141, Opcode_PRINTI = 178, Opcode_PRINTR = 179, Opcode_QUIT = 186, - Opcode_CRLF = 187 + Opcode_RTRUE = 176 }; diff --git a/zilasm/parser.cpp b/zilasm/parser.cpp index 9b976d9..1ea4aa7 100644 --- a/zilasm/parser.cpp +++ b/zilasm/parser.cpp @@ -18,25 +18,8 @@ * * SPDX-License-Identifier: AGPL-3.0-or-later */ -#include -#include /* fopen, fgets */ -#include /* strlen */ -#include -#include -#include -using namespace std; - -#include "header.h" -#include "parser.h" -#include "directives.h" - -extern "C" -{ -#include "opcodes.h" -} -#include "labels.h" -#include "string_table.h" +#include "include_all.h" #define iscomment(c) ((c) == ';') @@ -46,29 +29,58 @@ extern "C" //#define fatal_error(errmsg) printf(errmsg) #define PC NULL -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]); +void +CParser::add_function(const char *s) +{ + string name = ""; + s = pass_spaces(s); + while (*s != 0 && *s != ' ' && *s != '\n') + { + name += *s; + s++; + } + + unsigned memory_for_function = 1; + unsigned alignment = 0; + if (m_current_address & 3) + { + alignment = 4 - (m_current_address & 3); + memory_for_function += alignment; + } + + g_codes[g_number_of_instructions] = zmem_init(memory_for_function); + for ( int i = 0; i < memory_for_function; ++i) + zmem_putbyte(g_codes[g_number_of_instructions], 0); // output number of local variables + + + m_function_addresses.push_back(m_current_address + alignment); + Function f; + f.address = m_current_address + alignment; + f.index = g_number_of_instructions; + m_functions.insert(make_pair(name, f)); /// add key pair: function name and current instruction index + + m_current_address += memory_for_function; + ++g_number_of_instructions; +} + string -build_error_message(const char *message) +CParser::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); + g_parsing_contexts.top().current_file_name.c_str(), m_current_line_number, message); return string(buff); } void -fatal_error(const char *errmsg) +CParser::fatal_error(const char *errmsg) { printf( "%s\n", errmsg); g_haveErrors = true; @@ -77,7 +89,7 @@ fatal_error(const char *errmsg) void -checksep (const char *p) +CParser::checksep (const char *p) { if (!*p || iscomment (*p) || isspace (*p)) return; @@ -86,7 +98,7 @@ checksep (const char *p) const char * -pass_spaces (const char *p) +CParser::pass_spaces (const char *p) { while (p && isspace (*p)) p++; @@ -104,23 +116,42 @@ pass_alnums (const char *p) } -int tryparse_instruction (const char *a); - int -tryparse_directive (const char *p) +CParser::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); + Directive_handler f = m_pdirectives->directive_lookup (a, b - a); if (!f) return 0; - return (b-a) + (*f) (b); + return (b-a) + (*f) (b, this); } +int +CParser::tryparse_startup_directive(const char *p) +{ + const char *a = p; + string s = "%START::"; + if (memcmp(p, s.c_str(), s.length()) == 0) + { + p += s.length(); + while (isspace(*p)) + p++; + m_start_function_name = ""; + while (isalnum(*p)) + m_start_function_name += *p++; + + } + + return p - a; +} + + + int tryparse_assignment (const char *a, const char *b, const char *c) { @@ -129,7 +160,7 @@ tryparse_assignment (const char *a, const char *b, const char *c) int -tryparse_label (const char *a, const char *b, const char *c) +CParser::tryparse_label (const char *a, const char *b, const char *c) { if (*(c + 1) != ':') { @@ -152,7 +183,7 @@ tryparse_label (const char *a, const char *b, const char *c) int -tryparse_name (const char *a) +CParser::tryparse_name (const char *a) { const char *b = pass_alnums (a); const char *c = pass_spaces (b); @@ -167,14 +198,51 @@ tryparse_name (const char *a) } +int +CParser::read_instructions_parameter(char *a, string& str) +{ + int len = 0; + str = ""; + char *p = (char *)pass_spaces(a); + if (*p == '\"') + { + p++; + while (*p != '\"') + { + str += *p; + ++p; + } + len = p - a; + } + return len; +} + + int -tryparse_instruction (const char *a) +CParser::read_instructions_parameter2(char *a, string& str) +{ + int len = 0; + str = ""; + char *p = (char *)pass_spaces(a); + str=""; + + const char *b = pass_alnums(p); + str = string(p).substr(0, b - p); + + len = b - a; + return len; +} + +int +CParser::tryparse_instruction (const char *a) { bool display_error = false; int len = 0; const char *b = pass_alnums(a); if (b != a) { + string call_function_name = ""; + len = b ? b - a : strlen(a); ZOpcode *op = (ZOpcode *)symtable_lookup2(Opcodes, a, len); if (op) @@ -184,48 +252,45 @@ tryparse_instruction (const char *a) 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 == '\"') + case Opcode_CRLF: + case Opcode_PRINT: + case Opcode_QUIT: + case Opcode_RTRUE: + break; + + case Opcode_PRINTI: + case Opcode_PRINTR: { - p++; string str; - while (*p != '\"') - { - str += *p; - ++p; - } - len = p - a; - mem_additional = - String_table::encrypt_string(str.c_str(), NULL); + len += read_instructions_parameter((char *)a + len, str); + if ( str.length()) + mem_additional = String_table::encrypt_string(str.c_str(), NULL); + break; + } + case Opcode_ICALL1: + { + len += read_instructions_parameter2((char *)a + len, call_function_name); + m_calls.push_back(call_function_name); + mem_additional = zmem_init(2); // reserve two bytes of memory for the address + zmem_putbyte(mem_additional, 0); // and write there some two bytes, e.g. zeros + zmem_putbyte(mem_additional, 0); } break; + default: + { + display_error = true; + } } - 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); - + m_current_address += instruction_size; if (mem_additional) { for (int i = 0; i < mem_additional->used_size; ++i) @@ -234,13 +299,14 @@ tryparse_instruction (const char *a) 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()); } @@ -267,7 +333,7 @@ tryparse_instruction (const char *a) * Line can be one from: Comment, Global label, Local label, Directive, Name=Value, Instruction */ int -parse_line (const char *p) +CParser::parse_line (const char *p) { for (; *p; p++) { @@ -277,6 +343,13 @@ parse_line (const char *p) continue; if (iscomment (c)) return 0; + if (c == '%') + { + if (n = tryparse_startup_directive(p)) + return n; + } + + if (n = tryparse_directive (p)) return n; if (n = tryparse_name (p)) @@ -291,7 +364,7 @@ parse_line (const char *p) #define MAX_LINESIZE 1024 int -parse_file (/*const char *filename*/) +CParser::parse_file () { if (g_parsing_contexts.size() > 0) { @@ -301,7 +374,7 @@ parse_file (/*const char *filename*/) if (fp) { - g_currentLineNumber = 0; + m_current_line_number = 0; //const int MAX_LINESIZE = 1024; char line[MAX_LINESIZE]; @@ -309,7 +382,7 @@ parse_file (/*const char *filename*/) while (g_stopParsing == 0 && fgets(line, MAX_LINESIZE, fp)) { - ++g_currentLineNumber; + ++m_current_line_number; if (newline_missing) fatal_error(build_error_message("line too long").c_str()); @@ -336,48 +409,125 @@ parse_file (/*const char *filename*/) return 0; } -/* -line_passed() { - skip_spaces(); - return (current_token == LINE_END || current_token == LINE_COMMENT); +CParser::CParser() +{ + g_number_of_instructions = 0; + m_current_line_number = 0; + m_current_address = 0; + g_haveErrors = false; + m_pdirectives = new CDirectives(this); } -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) -} - -*/ +CParser::~CParser () +{ + for (int i = 0; i < g_number_of_instructions; ++i) + { + zmem_destroy(g_codes[i]); + } + g_number_of_instructions = 0; + delete m_pdirectives; +} -void -init_parser () +ZMemblock ** +CParser::get_codes() { - g_number_of_instructions = 0; + return g_codes; } +unsigned +CParser::get_number_of_instructions() +{ + return g_number_of_instructions; +} + +bool +CParser::have_errors() +{ + return g_haveErrors; +} -void -relase_parser () +void +CParser::calculate_function_addresses() { - for (int i = 0; i < g_number_of_instructions; ++i) - { - zmem_destroy (g_codes[i]); - } - g_number_of_instructions = 0; + //unsigned address = 0; + ////map::iterator function_iter = m_functions.begin(); + //unsigned j = 0; + + // + //for (int i = 0; i < get_number_of_instructions(); ++i) + //{ + // //if (function_iter == m_functions.end()) + // //{ + // // break; + // //} + + // if (m_function_addresses[j] == address) + // { + // if (address & 3) + // address += 4 - (address & 3); + // + + // for (map::iterator function_iter = m_functions.begin(); function_iter != m_functions.end(); ++function_iter) + // { + // if (function_iter->second.index == i) + // { + // function_iter->second.address = address; + // break; + // } + // + // } + // m_function_addresses[j] = address; + // ++j; + // } + // address += g_codes[i]->used_size; + //} } + + +unsigned +CParser::output_codes(ZMemblock *zmem_code) +{ + unsigned code_size = 0; + map::iterator function_iter = m_functions.begin(); + unsigned address = 0; + + unsigned calls_index = 0; + for (int i = 0; i < get_number_of_instructions(); ++i) + { + ////if ( parser.) + //if (function_iter != m_functions.end()) + //{ + // if (function_iter->second.index == i) + // { + // /// write few bytes for alignment purposes + // for (int j = 0; j < function_iter->second.address - address; ++j) + // zmem_putbyte(zmem_code, 0); + // } + //} + + // write actual addresses to calls + if (g_codes[i]->contents[0] == Opcode_ICALL1) + { + //vector::iterator iter = find(m_function_addresses.begin(), m_function_addresses.end(), address); + unsigned target_addr = m_functions.find(m_calls[calls_index])->second.address >> 2; + g_codes[i]->contents[1] = (target_addr >> 8) & 255; + g_codes[i]->contents[2] = target_addr & 255; + ++calls_index; + } + + + for (int j = 0; j < g_codes[i]->used_size; ++j) + { + zmem_putbyte(zmem_code, g_codes[i]->contents[j]); + ++code_size; + } + } + + return code_size; +} \ No newline at end of file diff --git a/zilasm/parser.h b/zilasm/parser.h index 007d2ff..e867439 100644 --- a/zilasm/parser.h +++ b/zilasm/parser.h @@ -29,14 +29,72 @@ struct Instruction int size; }; -void init_parser (); +#define MAX_NUMBER_OF_INSTRUCTIONS 65536 -int parse_file();// const char *filename); +struct Function +{ + Function() : index(0), address(0), number_of_local_variables(0) + { + } -extern unsigned g_number_of_instructions; + unsigned index; + unsigned address; + unsigned number_of_local_variables; +}; -#define MAX_NUMBER_OF_INSTRUCTIONS 65536 -extern ZMemblock (*g_codes[MAX_NUMBER_OF_INSTRUCTIONS]); + +class CParser +{ +public: + CParser(); + ~CParser(); + void calculate_function_addresses(); + unsigned get_number_of_instructions(); + ZMemblock **get_codes(); + bool have_errors(); + unsigned output_codes(ZMemblock *zmem_code); + int parse_file(); + void add_function(const char *s); + unsigned m_current_line_number; + unsigned m_current_address; + + + map m_functions; + vector m_function_addresses; + string m_start_function_name; + +private: + unsigned g_number_of_instructions;// = 0; + + + ZMemblock(*g_codes[MAX_NUMBER_OF_INSTRUCTIONS]); + bool g_haveErrors; + CDirectives *m_pdirectives; + vector m_calls; // contains functions names' if current instruction is call/icall or empty string otherwise + + string build_error_message(const char *message); + void checksep(const char *p); + void fatal_error(const char *errmsg); + int parse_line(const char *p); + const char *pass_spaces(const char *p); + int read_instructions_parameter(char *a, string& str); + int read_instructions_parameter2(char *a, string& str); + int tryparse_directive(const char *p); + int tryparse_startup_directive(const char *p); + + int tryparse_name(const char *a); + int tryparse_label(const char *a, const char *b, const char *c); + int tryparse_instruction(const char *a); +}; + +//void init_parser (); + +//int parse_file();// const char *filename); + +//extern unsigned g_number_of_instructions; + + +//extern ZMemblock (*g_codes[MAX_NUMBER_OF_INSTRUCTIONS]); struct Parsing_Context { @@ -45,7 +103,7 @@ struct Parsing_Context }; extern stack g_parsing_contexts; -extern unsigned g_currentLineNumber; -extern bool g_haveErrors; +//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 ed2b6d7..4e2233d 100644 --- a/zilasm/string_table.cpp +++ b/zilasm/string_table.cpp @@ -90,13 +90,6 @@ String_table::encrypt_string (const char *str, ZMemblock * zmb) } else if (c == ' ') { - //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 -- 2.31.1