1 #ifdef RCSID
2 static char RCSid[] =
3 "$Header: d:/cvsroot/tads/tads3/test/TEST_PRS.CPP,v 1.4 1999/07/11 00:47:03 MJRoberts Exp $";
4 #endif
5 
6 /*
7  *   Copyright (c) 1999, 2002 Michael J. Roberts.  All Rights Reserved.
8  *
9  *   Please see the accompanying license file, LICENSE.TXT, for information
10  *   on using and copying this software.
11  */
12 /*
13 Name
14   test_prs.cpp - parser test
15 Function
16 
17 Notes
18 
19 Modified
20   05/01/99 MJRoberts  - Creation
21 */
22 
23 #include <stdlib.h>
24 #include <stdio.h>
25 
26 #include "os.h"
27 #include "t3std.h"
28 #include "tctok.h"
29 #include "resload.h"
30 #include "tcmain.h"
31 #include "tchostsi.h"
32 #include "tcglob.h"
33 #include "tcprs.h"
34 #include "tctarg.h"
35 #include "vmfile.h"
36 #include "tcunas.h"
37 #include "tct3unas.h"
38 #include "tcmake.h"
39 #include "vmimage.h"
40 #include "vmrunsym.h"
41 #include "t3test.h"
42 
43 
errexit(const char * msg)44 static void errexit(const char *msg)
45 {
46     printf("%s\n", msg);
47     exit(1);
48 }
49 
show_const(int level,CTcPrsNode * result)50 static void show_const(int level, CTcPrsNode *result)
51 {
52     CTPNListEle *ele;
53     int i;
54 
55     for (i = level*3 ; i != 0 ; --i)
56         printf(" ");
57 
58     if (result == 0)
59     {
60         printf("no value\n");
61     }
62     else if (result->is_const())
63     {
64         switch(result->get_const_val()->get_type())
65         {
66         case TC_CVT_UNK:
67             printf("unknown\n");
68             break;
69 
70         case TC_CVT_NIL:
71             printf("nil\n");
72             break;
73 
74         case TC_CVT_TRUE:
75             printf("true\n");
76             break;
77 
78         case TC_CVT_INT:
79             printf("int = %ld\n",
80                    result->get_const_val()->get_val_int());
81             break;
82 
83         case TC_CVT_SSTR:
84             printf("sstr = %.*s\n",
85                    (int)result->get_const_val()->get_val_str_len(),
86                    result->get_const_val()->get_val_str());
87             break;
88 
89         case TC_CVT_LIST:
90             printf("list: %d elements\n",
91                    result->get_const_val()->get_val_list()
92                    ->get_count());
93             for (ele = result->get_const_val()->get_val_list()->get_head() ;
94                  ele != 0 ; ele = ele->get_next())
95                 show_const(level + 1, ele->get_expr());
96             break;
97 
98         case TC_CVT_OBJ:
99             printf("object: %ld\n", result->get_const_val()->get_val_obj());
100             break;
101 
102         case TC_CVT_PROP:
103             printf("property id: %d\n",
104                    result->get_const_val()->get_val_prop());
105             break;
106 
107         case TC_CVT_FUNCPTR:
108             printf("function pointer: %.*s\n",
109                    (int)result->get_const_val()->get_val_funcptr_sym()
110                    ->get_sym_len(),
111                    result->get_const_val()->get_val_funcptr_sym()
112                    ->get_sym());
113             break;
114 
115         case TC_CVT_ANONFUNCPTR:
116             printf("anonymous function pointer\n");
117             break;
118         }
119     }
120     else
121         printf("Non-constant value\n");
122 }
123 
124 /*
125  *   node list entry
126  */
127 struct node_entry
128 {
node_entrynode_entry129     node_entry(CTcPrsNode *n, CTcTokFileDesc *d, long l)
130     {
131         node = n;
132         desc = d;
133         linenum = l;
134     }
135 
136     /* top-level parse node for this line */
137     CTcPrsNode *node;
138 
139     /* file and line of source where node started */
140     CTcTokFileDesc *desc;
141     long linenum;
142 
143     /* next entry in list */
144     node_entry *nxt;
145 };
146 
main(int argc,char ** argv)147 int main(int argc, char **argv)
148 {
149     CResLoader *res_loader;
150     CTcHostIfc *hostifc;
151     int curarg;
152     int fatal_error_count = 0;
153     node_entry *node_head = 0;
154     node_entry *node_tail = 0;
155     osfildef *fpout = 0;
156     CVmFile *imgfile = 0;
157     ulong next_obj_id = 1;
158     uint next_prop_id = 1;
159     int next_local = 0;
160     CTcTokFileDesc *desc;
161     long linenum;
162     CTcUnasSrcCodeStr *unas_in;
163     CTcUnasOutStdio unas_out;
164     char pathbuf[OSFNMAX];
165 
166     /* initialize for testing */
167     test_init();
168 
169     /* create the host interface object */
170     hostifc = new CTcHostIfcStdio();
171 
172     /* create a resource loader */
173     os_get_special_path(pathbuf, sizeof(pathbuf), argv[0], OS_GSP_T3_RES);
174     res_loader = new CResLoader(pathbuf);
175 
176     /* initialize the compiler */
177     CTcMain::init(hostifc, res_loader, 0);
178 
179     /* create the disassembler input stream */
180     unas_in = new CTcUnasSrcCodeStr(G_cs);
181 
182     err_try
183     {
184         /* scan -I arguments */
185         for (curarg = 1 ; curarg < argc ; ++curarg)
186         {
187             char *p;
188 
189             /* get the argument string for easy reference */
190             p = argv[curarg];
191 
192             /* if it's not an option, we're done */
193             if (*p != '-')
194                 break;
195 
196             /* if it's a -I argument, use it */
197             if (*(p + 1) == 'I')
198             {
199                 char *path;
200 
201                 /*
202                  *   if it's with this argument, read it, otherwise move
203                  *   on to the next argument
204                  */
205                 if (*(p + 2) == '\0')
206                     path = argv[++curarg];
207                 else
208                     path = p + 2;
209 
210                 /* add the directory to the include path list */
211                 G_tok->add_inc_path(path);
212             }
213             else if (*(p + 1) == 'v')
214             {
215                 /* set verbose mode */
216                 G_tcmain->set_verbosity(TRUE);
217             }
218             else
219             {
220                 /*
221                  *   invalid usage - consume all the arguments and fall
222                  *   through to the usage checker
223                  */
224                 curarg = argc;
225                 break;
226             }
227         }
228 
229         /* check arguments */
230         if (curarg + 2 != argc)
231         {
232             /* terminate the compiler */
233             CTcMain::terminate();
234 
235             /* delete our objects */
236             delete res_loader;
237 
238             /* exit with an error */
239             errexit("usage: test_prs [options] <source-file> <image-file>\n"
240                     "options:\n"
241                     "   -Idir  - add dir to include path\n"
242                     "   -v     - verbose error messages");
243         }
244 
245         /* set up the tokenizer with the main input file */
246         if (G_tok->set_source(argv[curarg], argv[curarg]))
247             errexit("unable to open source file");
248 
249         /* set up an output file */
250         fpout = osfopwb(argv[curarg+1], OSFTT3IMG);
251         if (fpout == 0)
252             errexit("unable to open image file");
253         imgfile = new CVmFile();
254         imgfile->set_file(fpout, 0);
255 
256         /* read the first token */
257         G_tok->next();
258 
259         /* parse expressions */
260         for (;;)
261         {
262             CTcPrsNode *result;
263             CTcSymbol *entry;
264 
265             /* if we're at end of file, we're done */
266             if (G_tok->getcur()->gettyp() == TOKT_EOF)
267                 break;
268 
269             /* check for our fake declarations */
270             switch(G_tok->getcur()->gettyp())
271             {
272             case TOKT_OBJECT:
273                 /* add an object symbol */
274                 G_tok->next();
275                 entry = new CTcSymObj(G_tok->getcur()->get_text(),
276                                       G_tok->getcur()->get_text_len(),
277                                       FALSE, next_obj_id++, FALSE,
278                                       TC_META_TADSOBJ, 0);
279                 G_prs->get_global_symtab()->add_entry(entry);
280 
281                 /* skip the object name */
282                 G_tok->next();
283                 break;
284 
285             case TOKT_FUNCTION:
286                 /* add a function symbol */
287                 G_tok->next();
288                 entry = new CTcSymFunc(G_tok->getcur()->get_text(),
289                                        G_tok->getcur()->get_text_len(),
290                                        FALSE, 0, FALSE, TRUE, FALSE);
291                 G_prs->get_global_symtab()->add_entry(entry);
292 
293                 /* skip the function name */
294                 G_tok->next();
295                 break;
296 
297             case TOKT_LOCAL:
298                 /* add a local variable symbol */
299                 G_tok->next();
300                 entry = new CTcSymLocal(G_tok->getcur()->get_text(),
301                                         G_tok->getcur()->get_text_len(),
302                                         FALSE, FALSE, next_local++);
303                 G_prs->get_global_symtab()->add_entry(entry);
304 
305                 /* skip the function name */
306                 G_tok->next();
307                 break;
308 
309             default:
310                 /* note the starting line */
311                 desc = G_tok->get_last_desc();
312                 linenum = G_tok->get_last_linenum();
313 
314                 /* parse an expression */
315                 result = G_prs->parse_expr();
316 
317                 /* add it to our list */
318                 if (result != 0)
319                 {
320                     node_entry *cur;
321 
322                     /* create a new list entry */
323                     cur = new node_entry(result, desc, linenum);
324 
325                     /* link it at the end of our list */
326                     cur->nxt = 0;
327                     if (node_tail != 0)
328                         node_tail->nxt = cur;
329                     else
330                         node_head = cur;
331                     node_tail = cur;
332                 }
333             }
334 
335             /* parse a semicolon */
336             if (G_prs->parse_req_sem())
337                 break;
338         }
339 
340         /*
341          *   if there were no parse errors, run through our node list and
342          *   generate code
343          */
344         if (G_tcmain->get_error_count() == 0)
345         {
346             /*
347              *   loop through our node list; generate code and then delete
348              *   each list entry
349              */
350             while (node_head != 0)
351             {
352                 node_entry *nxt;
353 
354                 /* remember the next entry */
355                 nxt = node_head->nxt;
356 
357                 /*
358                  *   set this line's descriptor as current, for error
359                  *   reporting purposes
360                  */
361                 G_tok->set_line_info(node_head->desc, node_head->linenum);
362 
363                 /* fold symbolic constants */
364                 node_head->node =
365                     node_head->node
366                     ->fold_constants(G_prs->get_global_symtab());
367 
368                 /* if it's a constant value, display it */
369                 show_const(0, node_head->node);
370 
371                 /*
372                  *   generate code; for testing purposes, don't discard
373                  *   anything, to ensure we perform all generation
374                  */
375                 node_head->node->gen_code(FALSE, FALSE);
376 
377                 /* disassemble this much */
378                 unas_out.print("// line %lu\n", node_head->linenum);
379                 CTcT3Unasm::disasm(unas_in, &unas_out);
380 
381                 /* delete this entry */
382                 delete node_head;
383 
384                 /* move on to the next entry */
385                 node_head = nxt;
386             }
387         }
388     }
389     err_catch(exc)
390     {
391         /*
392          *   if it's not a general internal or fatal error, log it; don't
393          *   log general errors, since these will have been logged as
394          *   specific internal errors before being thrown
395          */
396         if (exc->get_error_code() != TCERR_INTERNAL_ERROR
397             && exc->get_error_code() != TCERR_FATAL_ERROR)
398             G_tok->log_error(TC_SEV_FATAL, exc->get_error_code());
399 
400         /* count the fatal error */
401         ++fatal_error_count;
402     }
403     err_end;
404 
405     /* report errors */
406     fprintf(stderr,
407             "Warnings: %d\n"
408             "Errors:   %d\n"
409             "Longest string: %d, longest list: %d\n",
410             G_tcmain->get_warning_count(),
411             G_tcmain->get_error_count() + fatal_error_count,
412             G_cg->get_max_str_len(), G_cg->get_max_list_cnt());
413 
414     /* delete the disassembler input object */
415     delete unas_in;
416 
417     /* shut down the compiler */
418     CTcMain::terminate();
419 
420     /* done with the res loader */
421     delete res_loader;
422 
423     /* delete the image file */
424     delete imgfile;
425 
426     /* delete the host interface */
427     delete hostifc;
428 
429     /* show any unfreed memory */
430     t3_list_memory_blocks(0);
431 
432     /* success */
433     return 0;
434 }
435 
436 /*
437  *   dummy 'make' object implementation
438  */
write_build_config_to_sym_file(class CVmFile *)439 void CTcMake::write_build_config_to_sym_file(class CVmFile *)
440 {
441 }
442 
443 
444 
445 /* ------------------------------------------------------------------------ */
446 /*
447  *   dummy implementation of runtime symbol table
448  */
add_sym(const char *,size_t,const vm_val_t *)449 void CVmRuntimeSymbols::add_sym(const char *, size_t,
450                                 const vm_val_t *)
451 {
452 }
453 
454