2 * parser.c -- part of ZilUtils/ZilAsm
4 * Copyright (C) 2016 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 */
26 #include "directives.h"
30 #define iscomment(c) ((c) == '#')
31 #define isbindigit(c) ((c) == '0' || (c) == '1')
34 #define fatal_error(errmsg)
37 void checksep(const char *p)
39 if (!*p || iscomment(*p) || isspace(*p)) return;
40 fatal_error("wrong chars");
43 const char *pass_spaces(const char *p)
45 while(p && isspace(*p)) p++;
46 return (p && *p) ? p : NULL;
49 const char *pass_alnums(const char *p)
51 while(p && isalnum(*p)) p++;
52 return (p && *p) ? p : NULL;
55 int tryparse_directive(const char *p)
60 const char *b = pass_alnums(a);
62 Directive_handler f = directive_lookup(a, b - a);
67 int tryparse_assignment(const char *a, const char *b, const char *c)
72 int tryparse_label(const char *a, const char *b, const char *c)
75 symtable_add2(Local_labels, a, b - a, PC);
76 } else if (*(c+2) != ':') {
77 symtable_add2(Global_labels, a, b - a, PC);
79 fatal_error("wrong label type");
83 if (*c && ((c = pass_spaces(c)) != NULL) && *c)
84 return tryparse_instruction(c);
88 int tryparse_name(const char *a)
90 const char *b = pass_alnums(a);
91 const char *c = pass_spaces(b);
94 if (*c == '=') return tryparse_assignment(a, b, c + 1);
95 if (*c == ':') return tryparse_label(a, b, c);
99 int tryparse_instruction(const char *a)
101 const char *b = pass_alnums(a);
102 ZOpcode *op = symtable_lookup2(Opcodes, a, b - a);
104 ZOpcode_flags flags = op->flags;
110 * Line can be one from: Comment, Global label, Local label, Directive, Name=Value, Instruction
112 int parse_line(const char *p)
117 if (isspace(c)) continue;
118 if (iscomment(c)) return 0;
119 if (n = tryparse_directive(p)) return n;
120 if (n = tryparse_name(p)) return n; // ..label or assignment
121 if (n = tryparse_instruction(p)) return n;
122 fatal_error("wrong line");
127 int parse_file(const char *filename)
129 FILE *fp = fopen(filename, "r");
130 if (!fp) fatal_error("wrong file");
132 const int MAX_LINESIZE = 1024;
133 char line[MAX_LINESIZE];
134 int newline_missing = 0;
136 while (fgets(line, MAX_LINESIZE, fp)) {
137 if (newline_missing) fatal_error("line too long");
139 int n = strlen(line);
144 newline_missing = (line[n-1] != '\n');
154 return (current_token == LINE_END || current_token == LINE_COMMENT);
157 if (line_passed()) continue;
158 if (current_token == DIRECTIVE) {
159 if (!try_next_token(NAME))
160 fatal_error("directive contains incorrect chars")
161 handler = get_directive_handler(current_token);
163 fatal error("unknown directive");
164 (*handler)(remaining_line);
165 if (line_passed()) continue;
166 fatal_error("unexpected line tail");
167 } else if (current_token == NAME) {
169 if (current_token == ASSIGNMENT)