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 <stdio.h> /* fopen, fgets */
23 #include <string.h> /* strlen */
32 #include "directives.h"
39 #include "string_table.h"
42 #define iscomment(c) ((c) == ';')
43 #define isbindigit(c) ((c) == '0' || (c) == '1')
46 //#define fatal_error(errmsg) printf(errmsg)
49 unsigned g_number_of_instructions = 0;
51 unsigned g_currentLineNumber = 0;
52 //string g_source_directory;
53 bool g_haveErrors = false;
55 stack<Parsing_Context> g_parsing_contexts;
58 ZMemblock (*g_codes[MAX_NUMBER_OF_INSTRUCTIONS]);
61 build_error_message(const char *message)
64 sprintf(buff, "error at %s%s line %d: %s", g_parsing_contexts.top().current_directory.c_str(),
65 g_parsing_contexts.top().current_file_name.c_str(), g_currentLineNumber, message);
71 fatal_error(const char *errmsg)
73 printf( "%s\n", errmsg);
80 checksep (const char *p)
82 if (!*p || iscomment (*p) || isspace (*p))
84 fatal_error (build_error_message ("wrong chars").c_str());
89 pass_spaces (const char *p)
91 while (p && isspace (*p))
93 return (p && *p) ? p : NULL;
98 pass_alnums (const char *p)
100 while (p && isalnum (*p))
102 //return (p && *p) ? p : NULL;
107 int tryparse_instruction (const char *a);
110 tryparse_directive (const char *p)
114 const char *a = p + 1;
115 const char *b = pass_alnums (a);
117 Directive_handler f = directive_lookup (a, b - a);
120 return (b-a) + (*f) (b);
125 tryparse_assignment (const char *a, const char *b, const char *c)
132 tryparse_label (const char *a, const char *b, const char *c)
136 symtable_add2 (Local_labels, a, b - a, PC);
138 else if (*(c + 2) != ':')
140 symtable_add2 (Global_labels, a, b - a, PC);
144 fatal_error (build_error_message("wrong label type").c_str());
148 if (*c && ((c = pass_spaces (c)) != NULL) && *c)
149 return tryparse_instruction (c);
155 tryparse_name (const char *a)
157 const char *b = pass_alnums (a);
158 const char *c = pass_spaces (b);
163 return tryparse_assignment (a, b, c + 1);
165 return tryparse_label (a, b, c);
171 tryparse_instruction (const char *a)
173 bool display_error = false;
175 const char *b = pass_alnums(a);
178 len = b ? b - a : strlen(a);
179 ZOpcode *op = (ZOpcode *)symtable_lookup2(Opcodes, a, len);
182 ZOpcode_flags flags = op->flags;
183 ZMemblock *mem_additional = NULL;
195 char *p = (char *)a + len;
196 p = (char *)pass_spaces(p);
208 String_table::encrypt_string(str.c_str(), NULL);
214 display_error = true;
219 if (display_error == false)
222 int instruction_size = 1;
224 instruction_size += mem_additional->used_size;
226 g_codes[g_number_of_instructions] = zmem_init(instruction_size);
227 zmem_putbyte(g_codes[g_number_of_instructions], op->opcode);
231 for (int i = 0; i < mem_additional->used_size; ++i)
232 zmem_putbyte(g_codes[g_number_of_instructions],
233 mem_additional->contents[i]);
234 zmem_destroy(mem_additional);
237 ++g_number_of_instructions;
243 //display_error = true;
244 string message = "wrong line \"" + string(a) + string("\"");
245 fatal_error(build_error_message(message.c_str()).c_str());
254 char *instrcution_name = (char *)malloc(len + 1);
255 memcpy(instrcution_name, a, len);
256 instrcution_name[len] = 0;
257 string message = "instruction " + string(instrcution_name) + string(" is not supported yet");
258 fatal_error(build_error_message(message.c_str()).c_str());
259 free(instrcution_name);
267 * Line can be one from: Comment, Global label, Local label, Directive, Name=Value, Instruction
270 parse_line (const char *p)
280 if (n = tryparse_directive (p))
282 if (n = tryparse_name (p))
283 return n; // ..label or assignment
284 if (n = tryparse_instruction (p))
286 //fatal_error ("wrong line");
291 #define MAX_LINESIZE 1024
294 parse_file (/*const char *filename*/)
296 if (g_parsing_contexts.size() > 0)
298 string filename = g_parsing_contexts.top().current_directory + g_parsing_contexts.top().current_file_name;
300 FILE *fp = fopen(filename.c_str(), "r");
304 g_currentLineNumber = 0;
306 //const int MAX_LINESIZE = 1024;
307 char line[MAX_LINESIZE];
308 int newline_missing = 0;
310 while (g_stopParsing == 0 && fgets(line, MAX_LINESIZE, fp))
312 ++g_currentLineNumber;
315 fatal_error(build_error_message("line too long").c_str());
317 int n = strlen(line);
323 newline_missing = (line[n - 1] != '\n');
330 string message = string("can't open file ") + filename;
331 fatal_error(message.c_str());
334 g_parsing_contexts.pop();
343 return (current_token == LINE_END || current_token == LINE_COMMENT);
346 if (line_passed()) continue;
347 if (current_token == DIRECTIVE) {
348 if (!try_next_token(NAME))
349 fatal_error("directive contains incorrect chars")
350 handler = get_directive_handler(current_token);
352 fatal error("unknown directive");
353 (*handler)(remaining_line);
354 if (line_passed()) continue;
355 fatal_error("unexpected line tail");
356 } else if (current_token == NAME) {
358 if (current_token == ASSIGNMENT)
368 g_number_of_instructions = 0;
378 for (int i = 0; i < g_number_of_instructions; ++i)
380 zmem_destroy (g_codes[i]);
382 g_number_of_instructions = 0;