This is an Example of a Parser Written in C
The way the parser works, it reads one character at a time from an input stream. It skips separators (spaces, tab characters, etc...) until it sees a 'letter' or 'detector character'. It reads the token and identify it from a list of known keywords and stores a corresponding integer value into an array.
If the token starts with a number, a parenthesis, a sign, or the first letter is a token for a previously defined variable name, then the parser will evaluate (compute) the value of the mathematical expression, with order of precedence, and identify it as an expression with a corresponding value.
ARITHMETIC EXPRESSIONS
At any place where a numerical value is expected, it is possible to
supply an arithmetic expression.
To construct the expression, the following operators are available:
^ : power elevation (Utter most precedence)
*, / : multiplication, division (high precedence)
+, - : addition, subtraction (low precedence)
Also, some functions are available:
abs(arg) Returns the absolute value of arg.
sin(arg) Returns the sine of arg (arg is spec in degrees).
cos(arg)
tan(arg)
asin(arg)
acos(arg)
atan(arg)
sqr(arg) Returns the square of arg.
sqrt(arg) Returns the square root of arg.
Arithmetic expressions can include variables. To create a variable, you
simply assign a value to it. For example:
x = 4+3 # x = 7
y = sin(30)+x # y = 7.5
y = -y/2 # y = -3.75
pi = 4*atan(1) # pi = 3.14159265358979323846...
You can use any name for a variable as long as it is not a function
name (i.e. 'sin') or a command name (like 'quit').
You cannot insert space characters in an expression because they are
used as token separator.
It implements the following scripting language:
/mnt/archives/archives/to_class/Archives_part2/Windows/dp/unix/src/dtp/parser.c.html
1 #include <stdio.h>
2 #include <string.h>
3 #include <ctype.h>
4 #include <stdlib.h>
5 #include <math.h>
6 #include <unistd.h>
7
8 #include "parser.h"
9
10
11
12 typedef unsigned int UINT;
13 typedef enum { FALSE, TRUE } BOOLEAN;
14
15
16
17
18 #define DRAW 100
19 #define QUIT 101
20 #define UNITS 102
21 #define ORIGIN 103
22 #define ZOOM 104
23 #define HELP 105
24 #define TRANSLATE 106
25 #define ROTATE 107
26 #define FIT 108
27 #define PREVIEW 109
28 #define OUTPUT 110
29 #define SOURCE 111
30 #define PRINT 113
31 #define ASSIGN 114
32 #define CLS 115
33 #define LOAD 116
34 #define EXPR 117
35 #define VAR 118
36 #define MACH 119
37 #define OFF 120
38 #define OFFTAB 121
39 #define IN 122
40 #define MM 123
41 #define ISO 124
42 #define HP 125
43 #define TEK 126
44 #define SELECT 127
45 #define CLEARANCE 128
46 #define LOWERCASE_Z 129
47 #define UPPERCASE_Z 130
48 #define ZZ 131
49 #define VERIFY 132
50 #define APPEND 133
51 #define CLEAR 134
52 #define Z 135
53 #define XY 136
54 #define ON 137
55 #define REPORT 138
56 #define HPA 139
57 #define REGIME 140
58 #define DUMP 141
59 #define CENTER 142
60 #define WINDOW 143
61 #define CLIP 144
62 #define FRAME 145
63 #define CHANGEDIR 146
64 #define YES 147
65 #define NO 148
66 #define FLUSH 149
67 #define DRAWAXIS 150
68 #define TRACE 151
69 #define DISPLAY 152
70 #define PARTNAME 153
71 #define LENGTH 154
72 #define REFERENCE 155
73 #define KEEP 156
74 #define UNDO 157
75 #define HISTORY 158
76 #define STEPS 159
77 #define UNDEF 999
78
79 unsigned num_expr;
80 double exprval[16];
81 unsigned num_undef;
82 char undef_str[16][80];
83
84 #define NUMROUT 75
85 #define MAXTOKEN 10
86 unsigned int syntax[NUMROUT][MAXTOKEN] = {
87 {DRAW,NULL},
88 {DRAW,EXPR,NULL},
89 {DRAW,LOWERCASE_Z,EXPR,EXPR,NULL},
90 {DRAW,UPPERCASE_Z,EXPR,EXPR,EXPR,NULL},
91 {DRAW,ZZ,NULL},
92 {VERIFY,NULL},
93 {VERIFY,EXPR,NULL},
94 {VERIFY,LOWERCASE_Z,EXPR,EXPR,NULL},
95 {VERIFY,UPPERCASE_Z,EXPR,EXPR,EXPR,NULL},
96 {VERIFY,ZZ,NULL},
97 {QUIT,NULL},
98 {ZOOM,EXPR,NULL},
99 {LOWERCASE_Z,EXPR,NULL},
100 {ZOOM,EXPR,EXPR,EXPR,NULL},
101 {LOWERCASE_Z,EXPR,EXPR,EXPR,NULL},
102 {CLS,NULL},
103 {ISO,UNDEF,NULL},
104 {ISO,NULL},
105 {PREVIEW,NULL},
106 {UNDEF,ASSIGN,EXPR,NULL},
107 {VAR,ASSIGN,EXPR,NULL},
108 {HELP,NULL},
109 {SOURCE,UNDEF},
110 {MACH,EXPR,NULL},
111 {OFF,EXPR,NULL},
112 {OFFTAB,UNDEF,NULL},
113 {TRANSLATE,EXPR,EXPR,NULL},
114 {UNITS,IN,NULL},
115 {UNITS,MM,NULL},
116 {UNITS,XY,IN,NULL},
117 {UNITS,XY,MM,NULL},
118 {UNITS,LOWERCASE_Z,IN,NULL},
119 {UNITS,LOWERCASE_Z,MM,NULL},
120 {ORIGIN,EXPR,EXPR,NULL},
121 {SELECT,HP,NULL},
122 {SELECT,TEK,NULL},
123 {LOAD,UNDEF,NULL},
124 {CLEARANCE,EXPR,NULL},
125 {APPEND,YES,NULL},
126 {APPEND,NO,NULL},
127 {REPORT,YES,NULL},
128 {REPORT,NO,NULL},
129 {HPA,EXPR,NULL},
130 {REGIME,EXPR,NULL},
131 {DUMP,NULL},
132 {CENTER,YES,NULL},
133 {CENTER,NO,NULL},
134 {CENTER,KEEP,NULL},
135 {WINDOW,EXPR,EXPR,EXPR,EXPR,NULL},
136 {CLIP,YES,NULL},
137 {CLIP,NO,NULL},
138 {FRAME,YES,NULL},
139 {FRAME,NO,NULL},
140 {CHANGEDIR,UNDEF,NULL},
141 {FLUSH,NULL},
142 {CLEAR,NULL},
143 {DRAWAXIS,NULL},
144 {DRAWAXIS,EXPR,NULL},
145 {DRAWAXIS,LOWERCASE_Z,EXPR,EXPR,NULL},
146 {DRAWAXIS,UPPERCASE_Z,EXPR,EXPR,EXPR,NULL},
147 {DRAWAXIS,ZZ,NULL},
148 {TRACE,YES,NULL},
149 {TRACE,NO,NULL},
150 {DISPLAY,PARTNAME,YES,NULL},
151 {DISPLAY,PARTNAME,NO,NULL},
152 {DISPLAY,LENGTH,YES,NULL},
153 {DISPLAY,LENGTH,NO,NULL},
154 {DISPLAY,REFERENCE,YES,NULL},
155 {DISPLAY,REFERENCE,NO,NULL},
156 {UNDO,NULL},
157 {UNDO,EXPR,NULL},
158 {HISTORY,NULL},
159 {DISPLAY,STEPS,YES,NULL},
160 {DISPLAY,STEPS,NO,NULL},
161 {NULL}
162 };
163
164
165 unsigned int pline[MAXTOKEN];
166 unsigned int num_pline;
167
168 VAR_TREE *var_tree_root = NULL;
169
170 BOOLEAN very_first_token = TRUE;
171
172 #define istoken(c) (isalpha(c) || c == '_' || c == '=' || c == '.' || isdigit(c) ||\
173 ((!very_first_token && (pline[0] == CHANGEDIR || pline[0] == ISO)) ? c == '/' : c == '='))
174
175
176
177 VAR_TREE *isvar (VAR_TREE *root, char *name);
178 void print_var (VAR_TREE *root);
179 signed int isfunc (char *funcname);
180 signed int isresword (char *resword);
181 double evalfunc (double funcarg, signed int functag);
182 void init_finfo (void);
183 int nextc (FILE *stream);
184 int __getc (FILE *stream);
185 char *gettoken (FILE *stream);
186 double getnum (FILE *stream);
187 double getfactor (FILE *stream);
188 double getpower (FILE *stream);
189 double getterm (FILE *stream);
190 double getexpr (FILE *stream);
191 signed ident_routine (unsigned *pline);
192 BOOLEAN syntaxcmp (unsigned *a, unsigned *b);
193
194 void def_var (VAR_TREE **root, char *name, double val)
195 {
196 if (*root == NULL) {
197 *root = (VAR_TREE *)malloc(sizeof(VAR_TREE));
198 strcpy((*root)->name,name);
199 (*root)->val = val;
200 (*root)->left = (*root)->right = NULL;
201 }
202 else if (strcmp(name,(*root)->name)<0)
203 def_var(&(*root)->left,name,val);
204 else if (strcmp(name,(*root)->name)>0)
205 def_var(&(*root)->right,name,val);
206 else {
207
208
209
210
211 (*root)->val = val;
212 }
213 }
214
215 VAR_TREE *isvar (VAR_TREE *root, char *name)
216 {
217 if (root == NULL)
218 return(NULL);
219 else if (strcmp(name,root->name)<0)
220 return(isvar(root->left,name));
221 else if (strcmp(name,root->name)>0)
222 return(isvar(root->right,name));
223 else
224 return(root);
225 }
226
227 void print_var (VAR_TREE *root)
228 {
229 if (root == NULL)
230 return;
231 print_var(root->left);
232 printf("\033[1m%s\033[0m = %lf\n",root->name,root->val);
233 print_var(root->right);
234 }
235
236 double PI_over_180 = M_PI/180;
237 #define degtorad(theta) (theta * PI_over_180)
238 #define radtodeg(theta) (theta * 180 / M_PI)
239
240 #define NUMFUNC 11
241 char *funcnames [] = { "abs", "sin", "cos", "tan", "sqr","atan","asin","acos","atn","asn","acs"};
242 signed int isfunc (char *funcname)
243 {
244 unsigned int i = 0;
245 BOOLEAN found = FALSE;
246 signed int functag = -1;
247 do {
248 if (strcmp(funcname,funcnames[i])==0) {
249 functag = i;
250 found = TRUE;
251 }
252 else
253 i++;
254 } while (!found && i < NUMFUNC);
255 return(functag);
256 }
257
258 #define NUMRESWORDS 82
259 char *reswords [] = { "draw", "d",
260 "quit", "q",
261 "units", "u",
262 "origin", "or",
263 "zoom",
264 "help",
265 "tr",
266 "preview", "p",
267 "source", "s",
268 "print",
269 "cls",
270 "load", "l",
271 "mach", "m",
272 "off", "o",
273 "offtab", "ot",
274 "in",
275 "mm",
276 "iso", "i",
277 "hp",
278 "tek",
279 "select", "sel",
280 "cl",
281 "z",
282 "Z",
283 "zz",
284 "verify", "v",
285 "append", "a",
286 "xy",
287 "on",
288 "report", "rep",
289 "hpa",
290 "regime", "reg",
291 "dump",
292 "center", "c",
293 "window", "w",
294 "clip",
295 "frame",
296 "cid",
297 "yes", "y",
298 "no", "n",
299 "flush", "f",
300 "clear",
301 "drawaxis", "da",
302 "trace",
303 "display","di",
304 "pn",
305 "length","len",
306 "ref","r",
307 "keep","k",
308 "undo","un",
309 "history","h",
310 "steps", "st",
311 "=" };
312 signed ressymbols [] = { DRAW, DRAW,
313 QUIT, QUIT,
314 UNITS, UNITS,
315 ORIGIN, ORIGIN,
316 ZOOM,
317 HELP,
318 TRANSLATE,
319 PREVIEW, PREVIEW,
320 SOURCE, SOURCE,
321 PRINT,
322 CLS,
323 LOAD, LOAD,
324 MACH, MACH,
325 OFF, OFF,
326 OFFTAB, OFFTAB,
327 IN,
328 MM,
329 ISO, ISO,
330 HP,
331 TEK,
332 SELECT, SELECT,
333 CLEARANCE,
334 LOWERCASE_Z,
335 UPPERCASE_Z,
336 ZZ,
337 VERIFY, VERIFY,
338 APPEND, APPEND,
339 XY,
340 ON,
341 REPORT, REPORT,
342 HPA,
343 REGIME, REGIME,
344 DUMP,
345 CENTER, CENTER,
346 WINDOW, WINDOW,
347 CLIP,
348 FRAME,
349 CHANGEDIR,
350 YES, YES,
351 NO, NO,
352 FLUSH, FLUSH,
353 CLEAR,
354 DRAWAXIS, DRAWAXIS,
355 TRACE,
356 DISPLAY, DISPLAY,
357 PARTNAME,
358 LENGTH, LENGTH,
359 REFERENCE, REFERENCE,
360 KEEP, KEEP,
361 UNDO, UNDO,
362 HISTORY, HISTORY,
363 STEPS, STEPS,
364 ASSIGN };
365 signed int isresword (char *resword)
366 {
367 unsigned int i = 0;
368 BOOLEAN found = FALSE;
369 signed int wordtag = -1;
370 do {
371 if (strcmp(resword,reswords[i])==0) {
372 wordtag = i;
373 found = TRUE;
374 }
375 else
376 i++;
377 } while (!found && i < NUMRESWORDS);
378 if (!found)
379 return(wordtag);
380 else
381 return(ressymbols[wordtag]);
382 }
383
384
385 double evalfunc (double funcarg, signed int functag)
386 {
387 switch (functag) {
388 case 0 : return(fabs(funcarg));
389 case 1 : return(sin(degtorad(funcarg)));
390 case 2 : return(cos(degtorad(funcarg)));
391 case 3 : return(tan(degtorad(funcarg)));
392 case 4 : return(sqrt(funcarg));
393 case 5 :
394 case 8 : return(radtodeg(atan(funcarg)));
395 case 6 :
396 case 9 : return(radtodeg(asin(funcarg)));
397 case 7 :
398 case 10: return(radtodeg(acos(funcarg)));
399 case -1 : ;
400 }
401 }
402
403 UINT lnnum;
404 UINT foff;
405 UINT lnoff;
406
407 #define curc(stream) ungetc(getc(stream),stream)
408
409 int nextc (FILE *stream)
410 {
411 int c;
412 while (c = ungetc(getc(stream),stream), c == '\t')
413 __getc(stream);
414 return(c);
415 }
416
417
418
419 void init_finfo (void)
420 {
421 lnnum = 1;
422 foff = 0;
423 lnoff = 0;
424 }
425
426 int __getc (FILE *stream)
427 {
428 int c;
429 if ((c=getc(stream))=='\n') {
430 lnnum++;
431 lnoff=0;
432 #ifdef MSDOS
433 foff++;
434 #endif
435 }
436 lnoff++;
437 foff++;
438 return(c);
439 }
440
441 void ungettoken (char *s, FILE *stream)
442 {
443 unsigned i = strlen(s);
444 foff -= i;
445 lnoff -= i;
446 do {
447 ungetc(s[--i],stream);
448 } while (i > 0);
449 }
450
451 char *gettoken (FILE *stream)
452 {
453 char token[80];
454 unsigned int i = 0;
455 while (istoken(nextc(stream))) {
456 token[i++] = __getc(stream);
457 }
458 token[i] = NULL;
459 return(strdup(token));
460 }
461
462 double getnum (FILE *stream)
463 {
464 #define radix 10
465 double numvalue = 0;
466 unsigned int unaryminus = FALSE;
467 unsigned int scale = 0;
468 unsigned int i;
469 if (curc(stream)== '-') {
470 unaryminus = TRUE;
471 __getc(stream);
472 }
473 else
474 if (curc(stream) == '+')
475 __getc(stream);
476 while (isdigit(curc(stream)))
477 numvalue = radix * numvalue + __getc(stream) - '0';
478 if (curc(stream) == '.') {
479 __getc(stream);
480 while (isdigit(curc(stream))) {
481 numvalue = radix * numvalue + __getc(stream) - '0';
482 scale++;
483 }
484 for (i = 1; i <= scale; i++)
485 numvalue /= radix;
486 }
487 if (unaryminus)
488 numvalue = -numvalue;
489 return(numvalue);
490 #undef radix
491 }
492
493 double getfactor (FILE *stream)
494 {
495 double facval;
496 char *s;
497 VAR_TREE *var_ptr;
498 signed int functag;
499 double funcarg;
500 unsigned int unaryminus = FALSE;
501 if (nextc(stream) == '-') {
502 unaryminus = TRUE;
503 __getc(stream);
504 }
505 else if (nextc(stream) == '+')
506 __getc(stream);
507 if(isdigit(nextc(stream)) || nextc(stream) == '.')
508 facval = getnum(stream);
509 else if (nextc(stream) == '(') {
510 __getc(stream);
511 facval = getexpr(stream);
512 if (nextc(stream) == ')')
513 __getc(stream);
514 else
515 fprintf(stderr,"')' missing in expression.\n");
516 } else if (isalpha(nextc(stream))) {
517 s = gettoken(stream);
518 if ((functag = isfunc(s))!=-1) {
519 if (nextc(stream)=='(') {
520 __getc(stream);
521 funcarg = getexpr(stream);
522 if (nextc(stream) == ')')
523 __getc(stream);
524 else
525 fprintf(stderr,"')' missing of function argument.\n");
526 }
527 else
528 fprintf(stderr,"'(' missing of function argument.\n");
529 facval = evalfunc(funcarg,functag);
530 }
531 else if ((var_ptr = isvar(var_tree_root,s))!=NULL)
532 facval = var_ptr->val;
533 else {
534 fprintf(stderr,"Undefined variable '%s' in expression.\n",s);
535 facval = 0;
536 }
537 free(s);
538 }
539 if (unaryminus)
540 facval = -facval;
541 return(facval);
542 }
543
544 double getpower (FILE *stream)
545 {
546 double facval;
547 double exponent;
548 facval = getfactor(stream);
549 while(nextc(stream) == '^') {
550 __getc(stream);
551 exponent = getfactor(stream);
552 facval = pow(facval,exponent);
553 }
554 return(facval);
555 }
556
557 double getterm (FILE *stream)
558 {
559 double termval;
560 double nextfacval;
561 unsigned int op;
562 termval = getpower(stream);
563 while (nextc(stream) == '*' || nextc(stream) == '/') {
564 op = __getc(stream);
565 nextfacval = getpower(stream);
566 if (op == '*')
567 termval *= nextfacval;
568 else if (op == '/')
569 if (nextfacval != 0)
570 termval /= nextfacval;
571 else
572 fprintf(stderr,"Division by zero\n");
573 }
574 return(termval);
575 }
576
577 double getexpr (FILE *stream)
578 {
579 double exprval;
580 double nexttermval;
581 unsigned int op;
582 exprval = getterm(stream);
583 while (nextc(stream) == '+' || nextc(stream) == '-') {
584 op = __getc(stream);
585 nexttermval = getterm(stream);
586 if (op == '+')
587 exprval += nexttermval;
588 else
589 exprval -= nexttermval;
590 }
591 return(exprval);
592 }
593
594
595 void print_syntax (void)
596 {
597 unsigned i;
598 printf("pline[");
599 for (i=0; i< num_pline; i++) {
600 printf("%u ",pline[i]);
601 }
602 printf("]");
603 }
604
605 signed parse_cmd (char *cmdfile)
606 {
607 FILE *f;
608 char *s;
609 int c;
610 signed reswordtag;
611 unsigned i;
612 char shellcmd[80];
613 signed idrout;
614 extern char cmdlist_filename[80];
615 extern BOOLEAN undoing;
616
617
618 if((f=fopen(cmdfile,"rt"))==NULL) {
619 fprintf(stderr,"Cannot open '%s'.\n",cmdfile);
620 exit(1);
621 }
622
623 init_finfo();
624 num_pline = 0;
625 num_expr = 0;
626 num_undef = 0;
627 very_first_token = TRUE;
628 while((c=nextc(f))!=EOF) {
629 if (c == '#' && very_first_token) {
630
631 __getc(f);
632 while (c = __getc(f), !(c == '\n ' || c == EOF));
633 }
634 if (c == '!' && very_first_token) {
635 shellcmd[0] = NULL; i = 0; __getc(f);
636 while (c = __getc(f), !(c == '\n ' || c == EOF))
637 shellcmd[i++] = c;
638 shellcmd[i] = NULL;
639
640
641 printf("\033[;r");
642
643 clear_screen();
644
645 system(shellcmd);
646
647
648 printf("\033[1m\033[7mPress any key to return to DTP!\033[0m");
649 fflush(stdout);
650 setraw();
651 keystroke();
652 restore();
653 clear_screen();
654
655 printf("\033[;20r"); fflush(stdout);
656 print_status();
657
658 }
659 if (isalpha(c) || c == '_' || c == '=' || c == '.' || c == '/') {
660 s = gettoken(f);
661
662 if ((reswordtag = isresword(s))!=-1) {
663 if (!very_first_token && pline[0] == SOURCE) {
664
665 pline[num_pline++] = UNDEF;
666 strcpy(undef_str[num_undef++],s);
667 }
668 else
669 pline[num_pline++] = reswordtag;
670 }
671 else if (isfunc(s)!=-1) {
672 ungettoken(s,f);
673 exprval[num_expr++] = getexpr(f);
674 pline[num_pline++] = EXPR;
675 }
676 else if (isalpha(c) || isdigit(c) || c == '+' || c == '-' || c == '.' || c == '(' || c == '/') {
677 if (isalpha(c) && isvar(var_tree_root,s)==NULL) {
678 pline[num_pline++] = UNDEF;
679 strcpy(undef_str[num_undef++],s);
680 }
681 else if (very_first_token) {
682 pline[num_pline++] = VAR;
683 strcpy(undef_str[num_undef++],s);
684 }
685 else {
686 if (pline[0] == CHANGEDIR || pline[0] == ISO) {
687 pline[num_pline++] = UNDEF;
688 strcpy(undef_str[num_undef++],s);
689 }
690 else {
691 ungettoken(s,f);
692 exprval[num_expr++] = getexpr(f);
693 pline[num_pline++] = EXPR;
694 }
695 }
696 }
697
698 c=nextc(f);
699 free(s);
700 very_first_token = FALSE;
701 }
702 else if (isdigit(c) || c == '+' || c == '-' || c == '.' || c == '(') {
703 if (c == '.' && (pline[0] == CHANGEDIR || pline[0] == ISO)) {
704 pline[num_pline++] = UNDEF;
705 strcpy(undef_str[num_undef++],s);
706 }
707 else {
708 exprval[num_expr++] = getexpr(f);
709 pline[num_pline++] = EXPR;
710 }
711 }
712 else
713 __getc(f);
714 }
715 pline[num_pline++] = NULL;
716
717
718
719 if((idrout = ident_routine(pline))!= ROUT_NO_INSTRUCTION &&
720 !undoing && idrout != ROUT_HISTORY && idrout != ROUT_SOURCE
721 && idrout != -1) {
722
723 sprintf(shellcmd,"cat %s >> %s;echo | cat >> %s",cmdfile,cmdlist_filename,cmdlist_filename);
724 system(shellcmd);
725 }
726
727 fclose(f);
728 unlink(cmdfile);
729
730 return(idrout);
731
732 }
733
734
735 signed ident_routine (unsigned *pline)
736 {
737 unsigned i = 0;
738 while (i < NUMROUT) {
739 if (syntaxcmp(pline,syntax[i]))
740 return(i);
741 i++;
742 }
743 return(-1);
744 }
745
746
747 BOOLEAN syntaxcmp (unsigned *a, unsigned *b)
748 {
749 unsigned i = 0;
750 while (*(a+i) == *(b+i)) {
751 if (*(a+i) == NULL)
752 return(TRUE);
753 i++;
754 }
755 return(FALSE);
756 }