Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libexpr/extoken.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1989-2011 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* *
19
***********************************************************************/
20
#pragma prototyped
21
/*
22
* Glenn Fowler
23
* AT&T Research
24
*
25
* expression library default lexical analyzer
26
*/
27
28
#include "exlib.h"
29
30
#if !defined(TRACE_lex) && _BLD_DEBUG
31
#define TRACE_lex -10
32
#endif
33
34
#if TRACE_lex
35
36
/*
37
* trace c for op
38
*/
39
40
static void
41
trace(Expr_t* ex, int lev, char* op, int c)
42
{
43
char* s;
44
char* t;
45
char buf[16];
46
47
t = "";
48
switch (c)
49
{
50
case 0:
51
s = " EOF";
52
break;
53
case '=':
54
s = t = buf;
55
*t++ = ' ';
56
if (!lev && exlval.op != c)
57
*t++ = exlval.op;
58
*t++ = c;
59
*t = 0;
60
break;
61
case AND:
62
s = " AND ";
63
t = "&&";
64
break;
65
case DEC:
66
s = " DEC ";
67
t = "--";
68
break;
69
case DECLARE:
70
s = " DECLARE ";
71
t = exlval.id->name;
72
break;
73
case DYNAMIC:
74
s = " DYNAMIC ";
75
t = exlval.id->name;
76
break;
77
case EQ:
78
s = " EQ ";
79
t = "==";
80
break;
81
case FLOATING:
82
s = " FLOATING ";
83
sfsprintf(t = buf, sizeof(buf), "%f", exlval.floating);
84
break;
85
case GE:
86
s = " GE ";
87
t = ">=";
88
break;
89
case ID:
90
s = " ID ";
91
t = exlval.id->name;
92
break;
93
case INC:
94
s = "INC ";
95
t = "++";
96
break;
97
case INTEGER:
98
s = " INTEGER ";
99
sfsprintf(t = buf, sizeof(buf), "%I*d", sizeof(exlval.integer), exlval.integer);
100
break;
101
case LABEL:
102
s = " LABEL ";
103
t = exlval.id->name;
104
break;
105
case LE:
106
s = " LE ";
107
t = "<=";
108
break;
109
case LS:
110
s = " LS ";
111
t = "<<";
112
break;
113
case NAME:
114
s = " NAME ";
115
t = exlval.id->name;
116
break;
117
case NE:
118
s = " NE ";
119
t = "!=";
120
break;
121
case OR:
122
s = " OR ";
123
t = "||";
124
break;
125
case RS:
126
s = " RS ";
127
t = ">>";
128
break;
129
case STRING:
130
s = " STRING ";
131
t = fmtesc(exlval.string);
132
break;
133
case UNSIGNED:
134
s = " UNSIGNED ";
135
sfsprintf(t = buf, sizeof(buf), "%I*u", sizeof(exlval.integer), exlval.integer);
136
break;
137
case BREAK:
138
s = " break";
139
break;
140
case CASE:
141
s = " case";
142
break;
143
case CONTINUE:
144
s = " continue";
145
break;
146
case DEFAULT:
147
s = " default";
148
break;
149
case ELSE:
150
s = " else";
151
break;
152
case EXIT:
153
s = " exit";
154
break;
155
case FOR:
156
s = " for";
157
break;
158
case IF:
159
s = " if";
160
break;
161
case PRAGMA:
162
s = " pragma";
163
break;
164
case PRINTF:
165
s = " printf";
166
break;
167
case QUERY:
168
s = " query";
169
break;
170
case RETURN:
171
s = " return";
172
break;
173
case SPRINTF:
174
s = " sprintf";
175
break;
176
case SWITCH:
177
s = " switch";
178
break;
179
case WHILE:
180
s = " while";
181
break;
182
default:
183
if (c < 0177)
184
{
185
s = buf;
186
*s++ = c;
187
*s = 0;
188
t = fmtesc(buf);
189
s = " ";
190
}
191
break;
192
}
193
error(TRACE_lex + lev, "%s: [%d] %04d%s%s", op, ex->input->nesting, c, s, t);
194
}
195
196
/*
197
* trace wrapper for extoken()
198
*/
199
200
extern int _extoken_(Expr_t*);
201
202
int
203
extoken(Expr_t* ex)
204
{
205
int c;
206
207
#define extoken _extoken_
208
209
c = extoken(ex);
210
trace(ex, 0, "exlex", c);
211
return c;
212
}
213
214
#else
215
216
#define trace(p,a,b,c)
217
218
#endif
219
220
/*
221
* get the next expression char
222
*/
223
224
static int
225
lex(register Expr_t* ex)
226
{
227
register int c;
228
229
for (;;)
230
{
231
if (c = ex->input->peek)
232
ex->input->peek = 0;
233
else if (ex->input->pp)
234
{
235
if (!(c = *ex->input->pp++))
236
{
237
ex->input->pp = 0;
238
continue;
239
}
240
}
241
else if (ex->input->sp)
242
{
243
if (!(c = *ex->input->sp++))
244
{
245
if (!expop(ex))
246
continue;
247
else trace(ex, -1, "expop sp FAIL", 0);
248
ex->input->sp--;
249
}
250
}
251
else if (ex->input->fp)
252
{
253
if ((c = sfgetc(ex->input->fp)) == EOF)
254
{
255
if (!expop(ex))
256
continue;
257
else trace(ex, -1, "expop fp FAIL", 0);
258
c = 0;
259
}
260
else if ((ex->disc->flags & EX_INTERACTIVE) && c == '\n' && ex->input->next && !ex->input->next->next && ex->input->nesting <= 0)
261
{
262
error_info.line++;
263
expop(ex);
264
trace(ex, -1, "expop sp FORCE", 0);
265
c = 0;
266
}
267
}
268
else c = 0;
269
if (c == '\n')
270
setcontext(ex);
271
else if (c)
272
putcontext(ex, c);
273
trace(ex, -3, "ex--lex", c);
274
return c;
275
}
276
}
277
278
/*
279
* get the next expression token
280
*/
281
282
int
283
extoken(register Expr_t* ex)
284
{
285
register int c;
286
register char* s;
287
register int q;
288
int b;
289
char* e;
290
Dt_t* v;
291
292
if (ex->eof || ex->errors)
293
return 0;
294
again:
295
for (;;)
296
switch (c = lex(ex))
297
{
298
case 0:
299
goto eof;
300
case '/':
301
switch (q = lex(ex))
302
{
303
case '*':
304
for (;;) switch (lex(ex))
305
{
306
case '\n':
307
if (error_info.line)
308
error_info.line++;
309
else error_info.line = 2;
310
continue;
311
case '*':
312
switch (lex(ex))
313
{
314
case 0:
315
goto eof;
316
case '\n':
317
if (error_info.line)
318
error_info.line++;
319
else error_info.line = 2;
320
break;
321
case '*':
322
exunlex(ex, '*');
323
break;
324
case '/':
325
goto again;
326
}
327
break;
328
}
329
break;
330
case '/':
331
while ((c = lex(ex)) != '\n')
332
if (!c)
333
goto eof;
334
break;
335
default:
336
goto opeq;
337
}
338
/*FALLTHROUGH*/
339
case '\n':
340
if (error_info.line)
341
error_info.line++;
342
else error_info.line = 2;
343
/*FALLTHROUGH*/
344
case ' ':
345
case '\t':
346
break;
347
case '(':
348
case '{':
349
case '[':
350
ex->input->nesting++;
351
return exlval.op = c;
352
case ')':
353
case '}':
354
case ']':
355
ex->input->nesting--;
356
return exlval.op = c;
357
case '+':
358
case '-':
359
if ((q = lex(ex)) == c)
360
return exlval.op = c == '+' ? INC : DEC;
361
goto opeq;
362
case '*':
363
case '%':
364
case '^':
365
q = lex(ex);
366
opeq:
367
exlval.op = c;
368
if (q == '=')
369
c = '=';
370
else if (q == '%' && c == '%')
371
{
372
if (ex->input->fp)
373
ex->more = (const char*)ex->input->fp;
374
else ex->more = ex->input->sp;
375
goto eof;
376
}
377
else exunlex(ex, q);
378
return c;
379
case '&':
380
case '|':
381
if ((q = lex(ex)) == '=')
382
{
383
exlval.op = c;
384
return '=';
385
}
386
if (q == c)
387
c = c == '&' ? AND : OR;
388
else exunlex(ex, q);
389
return exlval.op = c;
390
case '<':
391
case '>':
392
if ((q = lex(ex)) == c)
393
{
394
exlval.op = c = c == '<' ? LS : RS;
395
if ((q = lex(ex)) == '=')
396
c = '=';
397
else exunlex(ex, q);
398
return c;
399
}
400
goto relational;
401
case '=':
402
case '!':
403
q = lex(ex);
404
relational:
405
if (q == '=') switch (c)
406
{
407
case '<':
408
c = LE;
409
break;
410
case '>':
411
c = GE;
412
break;
413
case '=':
414
c = EQ;
415
break;
416
case '!':
417
c = NE;
418
break;
419
}
420
else exunlex(ex, q);
421
return exlval.op = c;
422
case '#':
423
if (!ex->linewrap && !(ex->disc->flags & EX_PURE))
424
{
425
s = ex->linep - 1;
426
while (s > ex->line && isspace(*(s - 1)))
427
s--;
428
if (s == ex->line)
429
{
430
switch (extoken(ex))
431
{
432
case DYNAMIC:
433
case ID:
434
case NAME:
435
s = exlval.id->name;
436
break;
437
default:
438
s = "";
439
break;
440
}
441
if (streq(s, "include"))
442
{
443
if (extoken(ex) != STRING)
444
exerror("#%s: string argument expected", s);
445
else if (!expush(ex, exlval.string, 1, NiL, NiL))
446
{
447
setcontext(ex);
448
goto again;
449
}
450
}
451
else exerror("unknown directive");
452
}
453
}
454
return exlval.op = c;
455
case '\'':
456
case '"':
457
q = c;
458
sfstrseek(ex->tmp, 0, SEEK_SET);
459
ex->input->nesting++;
460
while ((c = lex(ex)) != q)
461
{
462
if (c == '\\')
463
{
464
sfputc(ex->tmp, c);
465
c = lex(ex);
466
}
467
if (!c)
468
{
469
exerror("unterminated %c string", q);
470
goto eof;
471
}
472
if (c == '\n')
473
{
474
if (error_info.line)
475
error_info.line++;
476
else error_info.line = 2;
477
}
478
sfputc(ex->tmp, c);
479
}
480
ex->input->nesting--;
481
s = exstash(ex->tmp, NiL);
482
if (q == '"' || (ex->disc->flags & EX_CHARSTRING))
483
{
484
if (!(exlval.string = vmstrdup(ex->vm, s)))
485
goto eof;
486
stresc(exlval.string);
487
return STRING;
488
}
489
exlval.integer = chrtoi(s);
490
return INTEGER;
491
case '.':
492
if (isdigit(c = lex(ex)))
493
{
494
sfstrseek(ex->tmp, 0, SEEK_SET);
495
sfputc(ex->tmp, '0');
496
sfputc(ex->tmp, '.');
497
goto floating;
498
}
499
exunlex(ex, c);
500
return exlval.op = '.';
501
case '0': case '1': case '2': case '3': case '4':
502
case '5': case '6': case '7': case '8': case '9':
503
sfstrseek(ex->tmp, 0, SEEK_SET);
504
sfputc(ex->tmp, c);
505
q = INTEGER;
506
b = 0;
507
if ((c = lex(ex)) == 'x' || c == 'X')
508
{
509
b = 16;
510
sfputc(ex->tmp, c);
511
for (;;)
512
{
513
switch (c = lex(ex))
514
{
515
case '0': case '1': case '2': case '3': case '4':
516
case '5': case '6': case '7': case '8': case '9':
517
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
518
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
519
sfputc(ex->tmp, c);
520
continue;
521
}
522
break;
523
}
524
}
525
else
526
{
527
while (isdigit(c))
528
{
529
sfputc(ex->tmp, c);
530
c = lex(ex);
531
}
532
if (c == '#')
533
{
534
s = exstash(ex->tmp, NiL);
535
b = strtol(s, NiL, 10);
536
do
537
{
538
sfputc(ex->tmp, c);
539
} while (isalnum(c = lex(ex)));
540
}
541
else
542
{
543
if (c == '.')
544
{
545
floating:
546
q = FLOATING;
547
sfputc(ex->tmp, c);
548
while (isdigit(c = lex(ex)))
549
sfputc(ex->tmp, c);
550
}
551
if (c == 'e' || c == 'E')
552
{
553
q = FLOATING;
554
sfputc(ex->tmp, c);
555
if ((c = lex(ex)) == '-' || c == '+')
556
{
557
sfputc(ex->tmp, c);
558
c = lex(ex);
559
}
560
while (isdigit(c))
561
{
562
sfputc(ex->tmp, c);
563
c = lex(ex);
564
}
565
}
566
}
567
}
568
s = exstash(ex->tmp, NiL);
569
if (q == FLOATING)
570
exlval.floating = strtod(s, &e);
571
else
572
{
573
if (c == 'u' || c == 'U')
574
{
575
q = UNSIGNED;
576
c = lex(ex);
577
exlval.integer = strtoull(s, &e, b);
578
}
579
else
580
exlval.integer = strtoll(s, &e, b);
581
if (*e)
582
{
583
*--e = 1;
584
exlval.integer *= strton(e, &e, NiL, 0);
585
}
586
}
587
exunlex(ex, c);
588
if (*e || isalpha(c) || c == '_' || c == '$')
589
{
590
exerror("%s: invalid numeric constant", s);
591
goto eof;
592
}
593
return q;
594
default:
595
if (isalpha(c) || c == '_' || c == '$')
596
{
597
sfstrseek(ex->tmp, 0, SEEK_SET);
598
sfputc(ex->tmp, c);
599
while (isalnum(c = lex(ex)) || c == '_' || c == '$')
600
sfputc(ex->tmp, c);
601
exunlex(ex, c);
602
s = exstash(ex->tmp, NiL);
603
v = expr.declare ? dtview(ex->symbols, NiL) : (Dt_t*)0;
604
exlval.id = (Exid_t*)dtmatch(ex->symbols, s);
605
if (v)
606
dtview(ex->symbols, v);
607
if (!exlval.id)
608
{
609
if (!(exlval.id = newof(0, Exid_t, 1, strlen(s) - EX_NAMELEN + 1)))
610
{
611
exnospace();
612
goto eof;
613
}
614
strcpy(exlval.id->name, s);
615
exlval.id->lex = NAME;
616
expr.statics += exlval.id->isstatic = expr.instatic;
617
618
/*
619
* LABELs are in the parent scope!
620
*/
621
622
if (c == ':' && !expr.nolabel && ex->frame && ex->frame->view)
623
dtinsert(ex->frame->view, exlval.id);
624
else
625
dtinsert(ex->symbols, exlval.id);
626
}
627
628
/*
629
* lexical analyzer state controlled by the grammar
630
*/
631
632
switch (exlval.id->lex)
633
{
634
case DECLARE:
635
if (exlval.id->index == CHAR)
636
{
637
/*
638
* `char*' === `string'
639
* the * must immediately follow char
640
*/
641
642
if (c == '*')
643
{
644
lex(ex);
645
exlval.id = id_string;
646
}
647
}
648
break;
649
case NAME:
650
/*
651
* action labels are disambiguated from ?:
652
* through the expr.nolabel grammar hook
653
* the : must immediately follow labels
654
*/
655
656
if (c == ':' && !expr.nolabel)
657
return LABEL;
658
break;
659
case PRAGMA:
660
/*
661
* user specific statement stripped and
662
* passed as string
663
*/
664
665
{
666
int b;
667
int n;
668
int pc;
669
int po;
670
int t;
671
672
/*UNDENT...*/
673
sfstrseek(ex->tmp, 0, SEEK_SET);
674
b = 1;
675
n = 0;
676
po = 0;
677
t = 0;
678
for (c = t = lex(ex);; c = lex(ex))
679
{
680
switch (c)
681
{
682
case 0:
683
goto eof;
684
case '/':
685
switch (q = lex(ex))
686
{
687
case '*':
688
for (;;)
689
{
690
switch (lex(ex))
691
{
692
case '\n':
693
if (error_info.line)
694
error_info.line++;
695
else error_info.line = 2;
696
continue;
697
case '*':
698
switch (lex(ex))
699
{
700
case 0:
701
goto eof;
702
case '\n':
703
if (error_info.line)
704
error_info.line++;
705
else error_info.line = 2;
706
continue;
707
case '*':
708
exunlex(ex, '*');
709
continue;
710
case '/':
711
break;
712
default:
713
continue;
714
}
715
break;
716
}
717
if (!b++)
718
goto eof;
719
sfputc(ex->tmp, ' ');
720
break;
721
}
722
break;
723
case '/':
724
while ((c = lex(ex)) != '\n')
725
if (!c)
726
goto eof;
727
if (error_info.line)
728
error_info.line++;
729
else error_info.line = 2;
730
b = 1;
731
sfputc(ex->tmp, '\n');
732
break;
733
default:
734
b = 0;
735
sfputc(ex->tmp, c);
736
sfputc(ex->tmp, q);
737
break;
738
}
739
continue;
740
case '\n':
741
if (error_info.line)
742
error_info.line++;
743
else error_info.line = 2;
744
b = 1;
745
sfputc(ex->tmp, '\n');
746
continue;
747
case ' ':
748
case '\t':
749
if (!b++)
750
goto eof;
751
sfputc(ex->tmp, ' ');
752
continue;
753
case '(':
754
case '{':
755
case '[':
756
b = 0;
757
if (!po)
758
{
759
switch (po = c)
760
{
761
case '(':
762
pc = ')';
763
break;
764
case '{':
765
pc = '}';
766
break;
767
case '[':
768
pc = ']';
769
break;
770
}
771
n++;
772
}
773
else if (c == po)
774
n++;
775
sfputc(ex->tmp, c);
776
continue;
777
case ')':
778
case '}':
779
case ']':
780
b = 0;
781
if (!po)
782
{
783
exunlex(ex, c);
784
break;
785
}
786
sfputc(ex->tmp, c);
787
if (c == pc && --n <= 0)
788
{
789
if (t == po)
790
break;
791
po = 0;
792
}
793
continue;
794
case ';':
795
b = 0;
796
if (!n)
797
break;
798
sfputc(ex->tmp, c);
799
continue;
800
case '\'':
801
case '"':
802
b = 0;
803
sfputc(ex->tmp, c);
804
ex->input->nesting++;
805
q = c;
806
while ((c = lex(ex)) != q)
807
{
808
if (c == '\\')
809
{
810
sfputc(ex->tmp, c);
811
c = lex(ex);
812
}
813
if (!c)
814
{
815
exerror("unterminated %c string", q);
816
goto eof;
817
}
818
if (c == '\n')
819
{
820
if (error_info.line)
821
error_info.line++;
822
else error_info.line = 2;
823
}
824
sfputc(ex->tmp, c);
825
}
826
ex->input->nesting--;
827
continue;
828
default:
829
b = 0;
830
sfputc(ex->tmp, c);
831
continue;
832
}
833
break;
834
}
835
(*ex->disc->reff)(ex, NiL, exlval.id, NiL, exstash(ex->tmp, NiL), 0, ex->disc);
836
837
/*..INDENT*/
838
}
839
goto again;
840
}
841
return exlval.id->lex;
842
}
843
return exlval.op = c;
844
}
845
eof:
846
ex->eof = 1;
847
return exlval.op = ';';
848
}
849
850