Added ability to define multiple functions (without parameters) and
[zilutils.git] / zilasm / parser.cpp
1 /*
2  * parser.c -- part of ZilUtils/ZilAsm
3  *
4  * Copyright (C) 2016, 2019, 2020 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
22 #include "include_all.h"
23
24
25 #define iscomment(c)   ((c) == ';')
26 #define isbindigit(c)  ((c) == '0' || (c) == '1')
27
28 /* !!! TODO !!! */
29 //#define fatal_error(errmsg) printf(errmsg)
30 #define PC NULL
31
32
33
34 stack<Parsing_Context> g_parsing_contexts;
35
36
37 void
38 CParser::add_function(const char *s)
39 {
40         string name = "";
41         s = pass_spaces(s);
42         while (*s != 0 && *s != ' ' && *s != '\n')
43         {
44                 name += *s;
45                 s++;
46         }
47         
48         unsigned memory_for_function = 1;
49         unsigned alignment = 0;
50         if (m_current_address & 3)
51         {
52                 alignment = 4 - (m_current_address & 3);
53                 memory_for_function += alignment;
54         }
55         
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
59         
60
61         m_function_addresses.push_back(m_current_address + alignment);
62         Function f;
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
66
67         m_current_address += memory_for_function;
68         ++g_number_of_instructions;
69 }
70
71
72 string
73 CParser::build_error_message(const char *message)
74 {
75         char buff[300];
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);
78         return string(buff);
79 }
80
81
82 void
83 CParser::fatal_error(const char *errmsg)
84 {
85         printf( "%s\n", errmsg);
86         g_haveErrors = true;
87 }
88
89
90
91 void
92 CParser::checksep (const char *p)
93 {
94   if (!*p || iscomment (*p) || isspace (*p))
95     return;
96   fatal_error (build_error_message ("wrong chars").c_str());
97 }
98
99
100 const char *
101 CParser::pass_spaces (const char *p)
102 {
103   while (p && isspace (*p))
104     p++;
105   return (p && *p) ? p : NULL;
106 }
107
108
109 const char *
110 pass_alnums (const char *p)
111 {
112   while (p && isalnum (*p))
113     p++;
114   //return (p && *p) ? p : NULL;
115   return p;
116 }
117
118
119 int
120 CParser::tryparse_directive (const char *p)
121 {
122   if (*p != '.')
123     return 0;
124   const char *a = p + 1;
125   const char *b = pass_alnums (a);
126   checksep (b);
127   Directive_handler f = m_pdirectives->directive_lookup (a, b - a);
128   if (!f)
129     return 0;
130   return (b-a) + (*f) (b, this);
131 }
132
133
134 int
135 CParser::tryparse_startup_directive(const char *p)
136 {
137         const char *a = p;
138         string s = "%START::";
139         if (memcmp(p, s.c_str(), s.length()) == 0)
140         {
141                 p += s.length();
142                 while (isspace(*p))
143                         p++;
144                 m_start_function_name = "";
145                 while (isalnum(*p))
146                         m_start_function_name += *p++;
147
148         }
149
150         return p - a;
151 }
152
153
154
155 int
156 tryparse_assignment (const char *a, const char *b, const char *c)
157 {
158   return 0;
159 }
160
161
162 int
163 CParser::tryparse_label (const char *a, const char *b, const char *c)
164 {
165   if (*(c + 1) != ':')
166     {
167       symtable_add2 (Local_labels, a, b - a, PC);
168     }
169   else if (*(c + 2) != ':')
170     {
171       symtable_add2 (Global_labels, a, b - a, PC);
172     }
173   else
174     {
175       fatal_error (build_error_message("wrong label type").c_str());
176     }
177
178   while (*c++ == ':');
179   if (*c && ((c = pass_spaces (c)) != NULL) && *c)
180     return tryparse_instruction (c);
181   return 1;
182 }
183
184
185 int
186 CParser::tryparse_name (const char *a)
187 {
188   const char *b = pass_alnums (a);
189   const char *c = pass_spaces (b);
190
191   if (!c)
192     return 0;
193   if (*c == '=')
194     return tryparse_assignment (a, b, c + 1);
195   if (*c == ':')
196     return tryparse_label (a, b, c);
197   return 0;
198 }
199
200
201 int 
202 CParser::read_instructions_parameter(char *a, string& str)
203 {
204         int len = 0;
205         str = "";
206         char *p = (char *)pass_spaces(a);
207         if (*p == '\"')
208         {
209                 p++;
210                 while (*p != '\"')
211                 {
212                         str += *p;
213                         ++p;
214                 }
215                 len = p - a;
216         }
217         return len;
218 }
219
220
221 int
222 CParser::read_instructions_parameter2(char *a, string& str)
223 {
224         int len = 0;
225         str = "";
226         char *p = (char *)pass_spaces(a);
227         str="";
228         
229         const char *b = pass_alnums(p);
230         str = string(p).substr(0, b - p);
231
232         len = b - a;
233         return len;
234 }
235
236 int
237 CParser::tryparse_instruction (const char *a)
238 {
239         bool display_error = false;
240         int len = 0;
241         const char *b = pass_alnums(a);
242         if (b != a)
243         {
244                 string call_function_name = "";
245
246                 len = b ? b - a : strlen(a);
247                 ZOpcode *op = (ZOpcode *)symtable_lookup2(Opcodes, a, len);
248                 if (op)
249                 {
250                         ZOpcode_flags flags = op->flags;
251                         ZMemblock *mem_additional = NULL;
252
253                         switch (op->opcode)
254                         {
255                                 case Opcode_CRLF:
256                                 case Opcode_PRINT:
257                                 case Opcode_QUIT:
258                                 case Opcode_RTRUE:
259                                         break;
260
261                                 case Opcode_PRINTI:
262                                 case Opcode_PRINTR:
263                                 {
264                                         string str;
265                                         len += read_instructions_parameter((char *)a + len, str);
266                                         if ( str.length())
267                                                 mem_additional = String_table::encrypt_string(str.c_str(), NULL);
268                                         break;
269                                 }
270                                 case Opcode_ICALL1:
271                                 {
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);
277                                 }
278                                 break;
279                                 default:
280                                 {
281                                         display_error = true;
282                                 }
283                         }
284
285                         if (display_error == false)
286                         {
287                                 int instruction_size = 1;
288                                 if (mem_additional)
289                                         instruction_size += mem_additional->used_size;
290
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;
294                                 if (mem_additional)
295                                 {
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);
300                                 }
301
302                                 
303
304                                 ++g_number_of_instructions;
305                                 return len;
306                         }
307                 }
308                 else
309                 {
310                         string message = "wrong line \"" + string(a) + string("\"");
311                         fatal_error(build_error_message(message.c_str()).c_str());
312                 }
313         }
314
315         if (display_error)
316         {
317                 char buff[300];
318                 if (len == 0)
319                         len = strlen(a);
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);
326         }
327
328         return strlen(a);
329 }
330
331
332 /*
333  *  Line can be one from: Comment, Global label, Local label, Directive, Name=Value, Instruction
334  */
335 int
336 CParser::parse_line (const char *p)
337 {
338   for (; *p; p++)
339     {
340       char c = *p;
341       int n;
342       if (isspace (c))
343         continue;
344       if (iscomment (c))
345         return 0;
346           if (c == '%')
347           {
348                   if (n = tryparse_startup_directive(p))
349                           return n;
350           }
351
352
353       if (n = tryparse_directive (p))
354         return n;
355       if (n = tryparse_name (p))
356         return n;               // ..label or assignment
357       if (n = tryparse_instruction (p))
358         return n;
359       //fatal_error ("wrong line");
360     }
361   return 0;
362 }
363
364 #define MAX_LINESIZE 1024
365
366 int
367 CParser::parse_file ()
368 {
369         if (g_parsing_contexts.size() > 0)
370         {
371                 string filename = g_parsing_contexts.top().current_directory + g_parsing_contexts.top().current_file_name;
372
373                 FILE *fp = fopen(filename.c_str(), "r");
374                 if (fp)
375                 {
376
377                         m_current_line_number = 0;
378
379                         //const int MAX_LINESIZE = 1024;
380                         char line[MAX_LINESIZE];
381                         int newline_missing = 0;
382
383                         while (g_stopParsing == 0 && fgets(line, MAX_LINESIZE, fp))
384                         {
385                                 ++m_current_line_number;
386
387                                 if (newline_missing)
388                                         fatal_error(build_error_message("line too long").c_str());
389
390                                 int n = strlen(line);
391                                 if (!n)
392                                         continue;
393
394                                 parse_line(line);
395
396                                 newline_missing = (line[n - 1] != '\n');
397                         }
398
399                         fclose(fp);
400                 }
401                 else
402                 {
403                         string message = string("can't open file ") + filename;
404                         fatal_error(message.c_str());
405                 }
406
407                 g_parsing_contexts.pop();
408         }
409         return 0;
410 }
411
412
413 CParser::CParser() 
414 {
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);
420 }
421
422
423 CParser::~CParser ()
424 {
425         for (int i = 0; i < g_number_of_instructions; ++i)
426         {
427                 zmem_destroy(g_codes[i]);
428         }
429         g_number_of_instructions = 0;
430         delete m_pdirectives;
431 }
432
433
434 ZMemblock **
435 CParser::get_codes()
436 {
437         return g_codes;
438 }
439
440
441 unsigned 
442 CParser::get_number_of_instructions()
443 {
444         return g_number_of_instructions;
445 }
446
447
448 bool 
449 CParser::have_errors()
450 {
451         return g_haveErrors;
452 }
453
454
455 void 
456 CParser::calculate_function_addresses()
457 {
458         //unsigned address = 0;
459         ////map<string, Function>::iterator function_iter = m_functions.begin();
460         //unsigned j = 0;
461
462         //
463         //for (int i = 0; i < get_number_of_instructions(); ++i)
464         //{
465         //      //if (function_iter == m_functions.end())
466         //      //{
467         //      //      break;
468         //      //}
469
470         //      if (m_function_addresses[j] == address)
471         //      {
472         //              if (address & 3)
473         //                      address += 4 - (address & 3);
474         //              
475
476         //              for (map<string, Function>::iterator function_iter = m_functions.begin(); function_iter != m_functions.end(); ++function_iter)
477         //              {
478         //                      if (function_iter->second.index == i)
479         //                      {
480         //                              function_iter->second.address = address;
481         //                              break;
482         //                      }
483         //      
484         //              }
485         //              m_function_addresses[j] = address;
486         //              ++j;
487         //      }
488         //      address += g_codes[i]->used_size;
489         //}
490 }
491
492
493 unsigned
494 CParser::output_codes(ZMemblock *zmem_code)
495 {
496         unsigned code_size = 0;
497         map<string, Function>::iterator function_iter = m_functions.begin();
498         unsigned address = 0;
499
500         unsigned calls_index = 0;
501         for (int i = 0; i < get_number_of_instructions(); ++i)
502         {
503                 ////if ( parser.)
504                 //if (function_iter != m_functions.end())
505                 //{
506                 //      if (function_iter->second.index == i)
507                 //      {
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);
511                 //      }
512                 //}
513
514                 // write actual addresses to calls
515                 if (g_codes[i]->contents[0] == Opcode_ICALL1)
516                 {
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;
521                         ++calls_index;
522                 }
523
524
525                 for (int j = 0; j < g_codes[i]->used_size; ++j)
526                 {
527                         zmem_putbyte(zmem_code, g_codes[i]->contents[j]);
528                         ++code_size;
529                 }
530         }
531
532         return code_size;
533 }