Updating to reflect the latest work
[zilutils.git] / zilasm / parser.cpp
1 /*
2  * parser.c -- part of ZilUtils/ZilAsm
3  *
4  * Copyright (C) 2016, 2019 Jason Self <j@jxself.org>
5  *
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.
10  *
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.
15  *
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/>
18  *
19  * SPDX-License-Identifier: AGPL-3.0-or-later
20  */
21 #include <stdlib.h>
22 #include <stdio.h>              /* fopen, fgets */
23 #include <string.h>             /* strlen */
24 #include <ctype.h>
25 #include <string>
26 using namespace std;
27
28
29 #include "header.h"
30 #include "parser.h"
31
32 extern "C"
33 {
34 #include "directives.h"
35 #include "opcodes.h"
36 }
37 #include "labels.h"
38 #include "string_table.h"
39
40
41 #define iscomment(c)   ((c) == ';')
42 #define isbindigit(c)  ((c) == '0' || (c) == '1')
43
44 /* !!! TODO !!! */
45 #define fatal_error(errmsg) printf(errmsg)
46 #define PC NULL
47
48 unsigned g_numberOfInstructions = 0;
49
50
51 ZMemblock (*g_codes[MAX_NUMBER_OF_INSTRUCTIONS]);
52
53
54 void
55 checksep (const char *p)
56 {
57   if (!*p || iscomment (*p) || isspace (*p))
58     return;
59   fatal_error ("wrong chars");
60 }
61
62
63 const char *
64 pass_spaces (const char *p)
65 {
66   while (p && isspace (*p))
67     p++;
68   return (p && *p) ? p : NULL;
69 }
70
71
72 const char *
73 pass_alnums (const char *p)
74 {
75   while (p && isalnum (*p))
76     p++;
77   return (p && *p) ? p : NULL;
78 }
79
80
81 int tryparse_instruction (const char *a);
82
83 int
84 tryparse_directive (const char *p)
85 {
86   if (*p != '.')
87     return 0;
88   const char *a = p + 1;
89   const char *b = pass_alnums (a);
90   checksep (b);
91   Directive_handler f = directive_lookup (a, b - a);
92   if (!f)
93     return 0;
94   return (*f) (b);
95 }
96
97
98 int
99 tryparse_assignment (const char *a, const char *b, const char *c)
100 {
101   return 0;
102 }
103
104
105 int
106 tryparse_label (const char *a, const char *b, const char *c)
107 {
108   if (*(c + 1) != ':')
109     {
110       symtable_add2 (Local_labels, a, b - a, PC);
111     }
112   else if (*(c + 2) != ':')
113     {
114       symtable_add2 (Global_labels, a, b - a, PC);
115     }
116   else
117     {
118       fatal_error ("wrong label type");
119     }
120
121   while (*c++ == ':');
122   if (*c && ((c = pass_spaces (c)) != NULL) && *c)
123     return tryparse_instruction (c);
124   return 1;
125 }
126
127
128 int
129 tryparse_name (const char *a)
130 {
131   const char *b = pass_alnums (a);
132   const char *c = pass_spaces (b);
133
134   if (!c)
135     return 0;
136   if (*c == '=')
137     return tryparse_assignment (a, b, c + 1);
138   if (*c == ':')
139     return tryparse_label (a, b, c);
140   return 0;
141 }
142
143
144 int
145 tryparse_instruction (const char *a)
146 {
147   const char *b = pass_alnums (a);
148   if (b != a)
149     {
150       int len = b ? b - a : strlen (a);
151       ZOpcode *op = (ZOpcode *) symtable_lookup2 (Opcodes, a, len);
152       if (!op)
153         return 0;
154       ZOpcode_flags flags = op->flags;
155       /* !!! TODO !!! */
156
157
158       ZMemblock *mem_additional = NULL;
159
160       switch (op->opcode)
161         {
162         case Opcode_CRLF:
163         case Opcode_PRINT:
164         case Opcode_QUIT:
165           break;
166
167         case Opcode_PRINTI:
168         case Opcode_PRINTR:
169           {
170             char *p = (char *) a + len;
171             p = (char *) pass_spaces (p);
172             if (*p == '\"')
173               {
174                 p++;
175                 string str;
176                 while (*p != '\"')
177                   {
178                     str += *p;
179                     ++p;
180                   }
181                 len = p - a;
182                 mem_additional =
183                   String_table::encrypt_string (str.c_str (), NULL);
184               }
185             break;
186           }
187         default:
188           fatal_error ("error! instruction not supported");
189           return 0;
190         }
191
192       int instruction_size = 1;
193       if (mem_additional)
194         instruction_size += mem_additional->used_size;
195       //printf("instruction %s", a);
196
197       g_codes[g_numberOfInstructions] = zmem_init (instruction_size);
198       zmem_putbyte (g_codes[g_numberOfInstructions], op->opcode);
199
200       if (mem_additional)
201         {
202           for (int i = 0; i < mem_additional->used_size; ++i)
203             zmem_putbyte (g_codes[g_numberOfInstructions],
204                           mem_additional->contents[i]);
205           zmem_destroy (mem_additional);
206         }
207
208       ++g_numberOfInstructions;
209       return len;
210     }
211
212   return 0;
213 }
214
215
216 /*
217  *  Line can be one from: Comment, Global label, Local label, Directive, Name=Value, Instruction
218  */
219 int
220 parse_line (const char *p)
221 {
222   for (; *p; p++)
223     {
224       char c = *p;
225       int n;
226       if (isspace (c))
227         continue;
228       if (iscomment (c))
229         return 0;
230       if (n = tryparse_directive (p))
231         return n;
232       if (n = tryparse_name (p))
233         return n;               // ..label or assignment
234       if (n = tryparse_instruction (p))
235         return n;
236       fatal_error ("wrong line");
237     }
238   return 0;
239 }
240
241 #define MAX_LINESIZE 1024
242
243 int
244 parse_file (const char *filename)
245 {
246   FILE *fp = fopen (filename, "r");
247   if (!fp)
248     fatal_error ("wrong file");
249
250   //const int MAX_LINESIZE = 1024;
251   char line[MAX_LINESIZE];
252   int newline_missing = 0;
253
254   while (fgets (line, MAX_LINESIZE, fp))
255     {
256       if (newline_missing)
257         fatal_error ("line too long");
258
259       int n = strlen (line);
260       if (!n)
261         continue;
262
263       parse_line (line);
264
265       newline_missing = (line[n - 1] != '\n');
266     }
267
268   fclose (fp);
269   return 0;
270 }
271
272 /*
273
274 line_passed() {
275     skip_spaces();
276     return (current_token == LINE_END || current_token == LINE_COMMENT);
277 }
278
279 if (line_passed()) continue;
280 if (current_token == DIRECTIVE) {
281     if (!try_next_token(NAME))
282         fatal_error("directive contains incorrect chars")
283     handler = get_directive_handler(current_token);
284     if (!handler)
285         fatal error("unknown directive");
286     (*handler)(remaining_line);
287     if (line_passed()) continue;
288     fatal_error("unexpected line tail");
289 } else if (current_token == NAME) {
290     skip_spaces();
291     if (current_token == ASSIGNMENT)
292 }
293     
294
295 */
296
297
298 void
299 init_parser ()
300 {
301   g_numberOfInstructions = 0;
302 }
303
304
305 void
306 relase_parser ()
307 {
308   for (int i = 0; i < g_numberOfInstructions; ++i)
309     {
310       zmem_destroy (g_codes[i]);
311     }
312   g_numberOfInstructions = 0;
313 }