X-Git-Url: https://jxself.org/git/?a=blobdiff_plain;f=zilasm%2Fparser.cpp;h=1ea4aa72aa3385af85d0a5437a1259f9c41c98fe;hb=HEAD;hp=31e257fd444623db965366e8b293d130f8b79032;hpb=82b0f84ab797141758929d16894d42e12ef79af7;p=zilutils.git diff --git a/zilasm/parser.cpp b/zilasm/parser.cpp index 31e257f..1ea4aa7 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 @@ -18,50 +18,87 @@ * * SPDX-License-Identifier: AGPL-3.0-or-later */ -#include -#include /* fopen, fgets */ -#include /* strlen */ -#include -#include -using namespace std; - -#include "header.h" -#include "parser.h" - -extern "C" -{ -#include "directives.h" -#include "opcodes.h" -} -#include "labels.h" -#include "string_table.h" +#include "include_all.h" #define iscomment(c) ((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; -ZMemblock (*g_codes[MAX_NUMBER_OF_INSTRUCTIONS]); +stack g_parsing_contexts; + + +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 +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(), m_current_line_number, message); + return string(buff); +} + + +void +CParser::fatal_error(const char *errmsg) +{ + printf( "%s\n", errmsg); + g_haveErrors = true; +} + void -checksep (const char *p) +CParser::checksep (const char *p) { if (!*p || iscomment (*p) || isspace (*p)) return; - fatal_error ("wrong chars"); + fatal_error (build_error_message ("wrong chars").c_str()); } const char * -pass_spaces (const char *p) +CParser::pass_spaces (const char *p) { while (p && isspace (*p)) p++; @@ -74,27 +111,47 @@ pass_alnums (const char *p) { while (p && isalnum (*p)) p++; - return (p && *p) ? p : NULL; + //return (p && *p) ? p : NULL; + return 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 (*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) { @@ -103,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) != ':') { @@ -115,7 +172,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++ == ':'); @@ -126,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); @@ -141,75 +198,134 @@ tryparse_name (const char *a) } -int -tryparse_instruction (const char *a) +int +CParser::read_instructions_parameter(char *a, string& str) { - 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) + int len = 0; + str = ""; + char *p = (char *)pass_spaces(a); + if (*p == '\"') { - 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; - } + { + 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; } + return len; +} - 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); +int +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; +} - if (mem_additional) +int +CParser::tryparse_instruction (const char *a) +{ + bool display_error = false; + int len = 0; + const char *b = pass_alnums(a); + if (b != a) { - for (int i = 0; i < mem_additional->used_size; ++i) - zmem_putbyte (g_codes[g_numberOfInstructions], - mem_additional->contents[i]); - zmem_destroy (mem_additional); + string call_function_name = ""; + + 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: + case Opcode_RTRUE: + break; + + case Opcode_PRINTI: + case Opcode_PRINTR: + { + string str; + 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; + } + } + + 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) + zmem_putbyte(g_codes[g_number_of_instructions], + mem_additional->contents[i]); + zmem_destroy(mem_additional); + } + + + + ++g_number_of_instructions; + return len; + } + } + else + { + string message = "wrong line \"" + string(a) + string("\""); + fatal_error(build_error_message(message.c_str()).c_str()); + } } - ++g_numberOfInstructions; - return len; - } + if (display_error) + { + 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); + } - return 0; + return strlen(a); } @@ -217,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++) { @@ -227,13 +343,20 @@ 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)) return n; // ..label or assignment if (n = tryparse_instruction (p)) return n; - fatal_error ("wrong line"); + //fatal_error ("wrong line"); } return 0; } @@ -241,73 +364,170 @@ parse_line (const char *p) #define MAX_LINESIZE 1024 int -parse_file (const char *filename) +CParser::parse_file () { - 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"); + m_current_line_number = 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)) + { + ++m_current_line_number; - 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; } -/* -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; } - -*/ + +ZMemblock ** +CParser::get_codes() +{ + return g_codes; +} -void -init_parser () +unsigned +CParser::get_number_of_instructions() { - g_numberOfInstructions = 0; + return g_number_of_instructions; } -void -relase_parser () +bool +CParser::have_errors() { - for (int i = 0; i < g_numberOfInstructions; ++i) - { - zmem_destroy (g_codes[i]); - } - g_numberOfInstructions = 0; + return g_haveErrors; } + + +void +CParser::calculate_function_addresses() +{ + //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