2 * parser.c -- part of ZilUtils/ZilAsm
4 * Copyright (C) 2016, 2019, 2020 Jason Self <j@jxself.org>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as
8 * published by the Free Software Foundation, either version 3 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>
19 * SPDX-License-Identifier: AGPL-3.0-or-later
22 #include "include_all.h"
25 #define iscomment(c) ((c) == ';')
26 #define isbindigit(c) ((c) == '0' || (c) == '1')
29 //#define fatal_error(errmsg) printf(errmsg)
34 stack<Parsing_Context> g_parsing_contexts;
38 CParser::add_function(const char *s)
42 while (*s != 0 && *s != ' ' && *s != '\n')
48 unsigned memory_for_function = 1;
49 unsigned alignment = 0;
50 if (m_current_address & 3)
52 alignment = 4 - (m_current_address & 3);
53 memory_for_function += alignment;
56 g_codes[g_number_of_instructions] = zmem_init(memory_for_function);
57 for ( int i = 0; i < memory_for_function; ++i)
58 zmem_putbyte(g_codes[g_number_of_instructions], 0); // output number of local variables
61 m_function_addresses.push_back(m_current_address + alignment);
63 f.address = m_current_address + alignment;
64 f.index = g_number_of_instructions;
65 m_functions.insert(make_pair(name, f)); /// add key pair: function name and current instruction index
67 m_current_address += memory_for_function;
68 ++g_number_of_instructions;
73 CParser::build_error_message(const char *message)
76 sprintf(buff, "error at %s%s line %d: %s", g_parsing_contexts.top().current_directory.c_str(),
77 g_parsing_contexts.top().current_file_name.c_str(), m_current_line_number, message);
83 CParser::fatal_error(const char *errmsg)
85 printf( "%s\n", errmsg);
92 CParser::checksep (const char *p)
94 if (!*p || iscomment (*p) || isspace (*p))
96 fatal_error (build_error_message ("wrong chars").c_str());
101 CParser::pass_spaces (const char *p)
103 while (p && isspace (*p))
105 return (p && *p) ? p : NULL;
110 pass_alnums (const char *p)
112 while (p && isalnum (*p))
114 //return (p && *p) ? p : NULL;
120 CParser::tryparse_directive (const char *p)
124 const char *a = p + 1;
125 const char *b = pass_alnums (a);
127 Directive_handler f = m_pdirectives->directive_lookup (a, b - a);
130 return (b-a) + (*f) (b, this);
135 CParser::tryparse_startup_directive(const char *p)
138 string s = "%START::";
139 if (memcmp(p, s.c_str(), s.length()) == 0)
144 m_start_function_name = "";
146 m_start_function_name += *p++;
156 tryparse_assignment (const char *a, const char *b, const char *c)
163 CParser::tryparse_label (const char *a, const char *b, const char *c)
167 symtable_add2 (Local_labels, a, b - a, PC);
169 else if (*(c + 2) != ':')
171 symtable_add2 (Global_labels, a, b - a, PC);
175 fatal_error (build_error_message("wrong label type").c_str());
179 if (*c && ((c = pass_spaces (c)) != NULL) && *c)
180 return tryparse_instruction (c);
186 CParser::tryparse_name (const char *a)
188 const char *b = pass_alnums (a);
189 const char *c = pass_spaces (b);
194 return tryparse_assignment (a, b, c + 1);
196 return tryparse_label (a, b, c);
202 CParser::read_instructions_parameter(char *a, string& str)
206 char *p = (char *)pass_spaces(a);
222 CParser::read_instructions_parameter2(char *a, string& str)
226 char *p = (char *)pass_spaces(a);
229 const char *b = pass_alnums(p);
230 str = string(p).substr(0, b - p);
237 CParser::tryparse_instruction (const char *a)
239 bool display_error = false;
241 const char *b = pass_alnums(a);
244 string call_function_name = "";
246 len = b ? b - a : strlen(a);
247 ZOpcode *op = (ZOpcode *)symtable_lookup2(Opcodes, a, len);
250 ZOpcode_flags flags = op->flags;
251 ZMemblock *mem_additional = NULL;
265 len += read_instructions_parameter((char *)a + len, str);
267 mem_additional = String_table::encrypt_string(str.c_str(), NULL);
272 len += read_instructions_parameter2((char *)a + len, call_function_name);
273 m_calls.push_back(call_function_name);
274 mem_additional = zmem_init(2); // reserve two bytes of memory for the address
275 zmem_putbyte(mem_additional, 0); // and write there some two bytes, e.g. zeros
276 zmem_putbyte(mem_additional, 0);
281 display_error = true;
285 if (display_error == false)
287 int instruction_size = 1;
289 instruction_size += mem_additional->used_size;
291 g_codes[g_number_of_instructions] = zmem_init(instruction_size);
292 zmem_putbyte(g_codes[g_number_of_instructions], op->opcode);
293 m_current_address += instruction_size;
296 for (int i = 0; i < mem_additional->used_size; ++i)
297 zmem_putbyte(g_codes[g_number_of_instructions],
298 mem_additional->contents[i]);
299 zmem_destroy(mem_additional);
304 ++g_number_of_instructions;
310 string message = "wrong line \"" + string(a) + string("\"");
311 fatal_error(build_error_message(message.c_str()).c_str());
320 char *instrcution_name = (char *)malloc(len + 1);
321 memcpy(instrcution_name, a, len);
322 instrcution_name[len] = 0;
323 string message = "instruction " + string(instrcution_name) + string(" is not supported yet");
324 fatal_error(build_error_message(message.c_str()).c_str());
325 free(instrcution_name);
333 * Line can be one from: Comment, Global label, Local label, Directive, Name=Value, Instruction
336 CParser::parse_line (const char *p)
348 if (n = tryparse_startup_directive(p))
353 if (n = tryparse_directive (p))
355 if (n = tryparse_name (p))
356 return n; // ..label or assignment
357 if (n = tryparse_instruction (p))
359 //fatal_error ("wrong line");
364 #define MAX_LINESIZE 1024
367 CParser::parse_file ()
369 if (g_parsing_contexts.size() > 0)
371 string filename = g_parsing_contexts.top().current_directory + g_parsing_contexts.top().current_file_name;
373 FILE *fp = fopen(filename.c_str(), "r");
377 m_current_line_number = 0;
379 //const int MAX_LINESIZE = 1024;
380 char line[MAX_LINESIZE];
381 int newline_missing = 0;
383 while (g_stopParsing == 0 && fgets(line, MAX_LINESIZE, fp))
385 ++m_current_line_number;
388 fatal_error(build_error_message("line too long").c_str());
390 int n = strlen(line);
396 newline_missing = (line[n - 1] != '\n');
403 string message = string("can't open file ") + filename;
404 fatal_error(message.c_str());
407 g_parsing_contexts.pop();
415 g_number_of_instructions = 0;
416 m_current_line_number = 0;
417 m_current_address = 0;
418 g_haveErrors = false;
419 m_pdirectives = new CDirectives(this);
425 for (int i = 0; i < g_number_of_instructions; ++i)
427 zmem_destroy(g_codes[i]);
429 g_number_of_instructions = 0;
430 delete m_pdirectives;
442 CParser::get_number_of_instructions()
444 return g_number_of_instructions;
449 CParser::have_errors()
456 CParser::calculate_function_addresses()
458 //unsigned address = 0;
459 ////map<string, Function>::iterator function_iter = m_functions.begin();
463 //for (int i = 0; i < get_number_of_instructions(); ++i)
465 // //if (function_iter == m_functions.end())
470 // if (m_function_addresses[j] == address)
473 // address += 4 - (address & 3);
476 // for (map<string, Function>::iterator function_iter = m_functions.begin(); function_iter != m_functions.end(); ++function_iter)
478 // if (function_iter->second.index == i)
480 // function_iter->second.address = address;
485 // m_function_addresses[j] = address;
488 // address += g_codes[i]->used_size;
494 CParser::output_codes(ZMemblock *zmem_code)
496 unsigned code_size = 0;
497 map<string, Function>::iterator function_iter = m_functions.begin();
498 unsigned address = 0;
500 unsigned calls_index = 0;
501 for (int i = 0; i < get_number_of_instructions(); ++i)
504 //if (function_iter != m_functions.end())
506 // if (function_iter->second.index == i)
508 // /// write few bytes for alignment purposes
509 // for (int j = 0; j < function_iter->second.address - address; ++j)
510 // zmem_putbyte(zmem_code, 0);
514 // write actual addresses to calls
515 if (g_codes[i]->contents[0] == Opcode_ICALL1)
517 //vector<unsigned>::iterator iter = find(m_function_addresses.begin(), m_function_addresses.end(), address);
518 unsigned target_addr = m_functions.find(m_calls[calls_index])->second.address >> 2;
519 g_codes[i]->contents[1] = (target_addr >> 8) & 255;
520 g_codes[i]->contents[2] = target_addr & 255;
525 for (int j = 0; j < g_codes[i]->used_size; ++j)
527 zmem_putbyte(zmem_code, g_codes[i]->contents[j]);