1// re2c $INPUT -o $OUTPUT -s
2/* re2c lesson 001_upn_calculator, calc_006, (c) M. Boerger 2006 - 2007 */
3/*!ignore:re2c
4
5- avoiding YYFILL()
6  . We use the inplace configuration re2c:yyfill to suppress generation of
7    YYFILL() blocks. This of course means we no longer have to provide the
8    macro.
9  . We also drop the YYMARKER stuff since we know that re2c does not generate
10    it for this example.
11  . Since re2c does no longer check for out of data situations we must do this.
12    For that reason we first reintroduce our zero rule and second we need to
13    ensure that the scanner does not take more than one bytes in one go.
14
15    In the example suppose "0" is passed. The scanner reads the first "0" and
16    then is in an undecided state. The scanner can earliest decide on the next
17    char what  the token is. In case of a zero the input ends and it was a
18    number, 0 to be precise. In case of a digit it is an octal number and the
19    next character needs to be read. In case of any other character the scanner
20    will detect an error with the any rule [^].
21
22    Now the above shows that the scanner may read two characters directly. But
23    only if the first is a "0". So we could easily check that if the first char
24    is "0" and the next char is a digit then yet another charcter is present.
25    But we require our inut to be zero terminated. And that means we do not
26    have to check anything for this scanner.
27
28    However with other rule sets re2c might read more then one character in a
29    row. In those cases it is normally hard to impossible to avoid YYFILL.
30
31- optimizing the generated code by using -s command line switch of re2c
32  . This tells re2c to generate code that uses if statements rather
33    then endless switch/case expressions where appropriate. Note that the
34    generated code now requires the input to be unsigned char rather than char
35    due to the way comparisons are generated.
36*/
37
38#include <stdlib.h>
39#include <stdio.h>
40#include <string.h>
41
42#define DEBUG(stmt) stmt
43
44int  stack[4];
45int  depth = 0;
46
47int push_num(const unsigned char *t, const unsigned char *l, int radix)
48{
49	int num = 0;
50
51	if (depth >= sizeof(stack))
52	{
53		return 3;
54	}
55
56	--t;
57	while(++t < l)
58	{
59		num = num * radix + (*t - (unsigned char)'0');
60	}
61	DEBUG(printf("Num: %d\n", num));
62
63	stack[depth++] = num;
64	return 0;
65}
66
67int stack_add()
68{
69	if (depth < 2) return 4;
70
71	--depth;
72	stack[depth-1] = stack[depth-1] + stack[depth];
73	DEBUG(printf("+\n"));
74	return 0;
75}
76
77int stack_sub()
78{
79	if (depth < 2) return 4;
80
81	--depth;
82	stack[depth-1] = stack[depth-1] - stack[depth];
83	DEBUG(printf("-\n"));
84	return 0;
85}
86
87int scan(char *s)
88{
89	unsigned char *p = (unsigned char*)s;
90	unsigned char *t;
91	int res = 0;
92
93#define YYCTYPE         unsigned char
94#define YYCURSOR        p
95
96	while(!res)
97	{
98		t = p;
99/*!re2c
100	re2c:indent:top    = 2;
101	re2c:yyfill:enable = 0;
102
103	DIGIT	= [0-9] ;
104	OCT		= "0" DIGIT+ ;
105	INT		= "0" | ( [1-9] DIGIT* ) ;
106	WS		= [ \t]+ ;
107
108	WS		{ continue; }
109	OCT		{ res = push_num(t, p, 8);	continue; }
110	INT		{ res = push_num(t, p, 10); continue; }
111	"+"		{ res = stack_add();		continue; }
112	"-"		{ res = stack_sub();		continue; }
113	"\000"  { res = depth == 1 ? 0 : 2;	break; }
114	[^]		{ res = 1; 					continue; }
115*/
116	}
117	return res;
118}
119
120int main(int argc, char **argv)
121{
122	if (argc > 1)
123	{
124		char *inp;
125		int res = 0, argp = 0, len;
126
127		while(!res && ++argp < argc)
128		{
129			inp = strdup(argv[argp]);
130			len = strlen(inp);
131			if (inp[0] == '\"' && inp[len-1] == '\"')
132			{
133				inp[len - 1] = '\0';
134				++inp;
135			}
136			res = scan(inp);
137			free(inp);
138		}
139		switch(res)
140		{
141		case 0:
142			printf("Result: %d\n", stack[0]);
143			return 0;
144		case 1:
145			fprintf(stderr, "Illegal character in input.\n");
146			return 1;
147		case 2:
148			fprintf(stderr, "Premature end of input.\n");
149			return 2;
150		case 3:
151			fprintf(stderr, "Stack overflow.\n");
152			return 3;
153		case 4:
154			fprintf(stderr, "Stack underflow.\n");
155			return 4;
156		}
157	}
158	else
159	{
160		fprintf(stderr, "%s <expr>\n", argv[0]);
161		return 0;
162	}
163}
164