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