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;
106 int tryparse_instruction (const char *a);
109 tryparse_directive (const char *p)
113 const char *a = p + 1;
114 const char *b = pass_alnums (a);
116 Directive_handler f = directive_lookup (a, b - a);
119 return (b-a) + (*f) (b);
124 tryparse_assignment (const char *a, const char *b, const char *c)
131 tryparse_label (const char *a, const char *b, const char *c)
135 symtable_add2 (Local_labels, a, b - a, PC);
137 else if (*(c + 2) != ':')
139 symtable_add2 (Global_labels, a, b - a, PC);
143 fatal_error (build_error_message("wrong label type").c_str());
147 if (*c && ((c = pass_spaces (c)) != NULL) && *c)
148 return tryparse_instruction (c);
154 tryparse_name (const char *a)
156 const char *b = pass_alnums (a);
157 const char *c = pass_spaces (b);
162 return tryparse_assignment (a, b, c + 1);
164 return tryparse_label (a, b, c);
170 tryparse_instruction (const char *a)
172 bool display_error = false;
174 const char *b = pass_alnums(a);
177 len = b ? b - a : strlen(a);
178 ZOpcode *op = (ZOpcode *)symtable_lookup2(Opcodes, a, len);
181 ZOpcode_flags flags = op->flags;
182 ZMemblock *mem_additional = NULL;
194 char *p = (char *)a + len;
195 p = (char *)pass_spaces(p);
207 String_table::encrypt_string(str.c_str(), NULL);
213 display_error = true;
218 if (display_error == false)
221 int instruction_size = 1;
223 instruction_size += mem_additional->used_size;
225 g_codes[g_number_of_instructions] = zmem_init(instruction_size);
226 zmem_putbyte(g_codes[g_number_of_instructions], op->opcode);
230 for (int i = 0; i < mem_additional->used_size; ++i)
231 zmem_putbyte(g_codes[g_number_of_instructions],
232 mem_additional->contents[i]);
233 zmem_destroy(mem_additional);
236 ++g_number_of_instructions;
242 //display_error = true;
243 string message = "wrong line \"" + string(a) + string("\"");
244 fatal_error(build_error_message(message.c_str()).c_str());
253 char *instrcution_name = (char *)malloc(len + 1);
254 memcpy(instrcution_name, a, len);
255 instrcution_name[len] = 0;
256 string message = "instruction " + string(instrcution_name) + string(" is not supported yet");
257 fatal_error(build_error_message(message.c_str()).c_str());
258 free(instrcution_name);
266 * Line can be one from: Comment, Global label, Local label, Directive, Name=Value, Instruction
269 parse_line (const char *p)
279 if (n = tryparse_directive (p))
281 if (n = tryparse_name (p))
282 return n; // ..label or assignment
283 if (n = tryparse_instruction (p))
285 //fatal_error ("wrong line");
290 #define MAX_LINESIZE 1024
293 parse_file (/*const char *filename*/)
295 if (g_parsing_contexts.size() > 0)
297 string filename = g_parsing_contexts.top().current_directory + g_parsing_contexts.top().current_file_name;
299 FILE *fp = fopen(filename.c_str(), "r");
303 g_currentLineNumber = 0;
305 //const int MAX_LINESIZE = 1024;
306 char line[MAX_LINESIZE];
307 int newline_missing = 0;
309 while (g_stopParsing == 0 && fgets(line, MAX_LINESIZE, fp))
311 ++g_currentLineNumber;
314 fatal_error(build_error_message("line too long").c_str());
316 int n = strlen(line);
322 newline_missing = (line[n - 1] != '\n');
329 string message = string("can't open file ") + filename;
330 fatal_error(message.c_str());
333 g_parsing_contexts.pop();
342 return (current_token == LINE_END || current_token == LINE_COMMENT);
345 if (line_passed()) continue;
346 if (current_token == DIRECTIVE) {
347 if (!try_next_token(NAME))
348 fatal_error("directive contains incorrect chars")
349 handler = get_directive_handler(current_token);
351 fatal error("unknown directive");
352 (*handler)(remaining_line);
353 if (line_passed()) continue;
354 fatal_error("unexpected line tail");
355 } else if (current_token == NAME) {
357 if (current_token == ASSIGNMENT)
367 g_number_of_instructions = 0;
377 for (int i = 0; i < g_number_of_instructions; ++i)
379 zmem_destroy (g_codes[i]);
381 g_number_of_instructions = 0;