1// re2c $INPUT -o $OUTPUT
2/* re2c lesson 001_upn_calculator, calc_005, (c) M. Boerger 2006 - 2007 */
3/*!ignore:re2c
4
5- turning this lesson into an easy calculator
6  . We are going to write an UPN calculator so we need an additional rule to
7    ignore white space.
8  . Then we need to store the scanned input somewhere and do our math on it.
9  . Also we need to scan all arguments since the main c code gets the input
10    split up into chunks.
11  . In contrast to what we did before we now add a variable res that holds the
12    scanner state. We initialize that variable to 0 and quit the loop when it
13    is non zero. This will also be our return value so that we can use it in
14    function main to generate error information.
15  . To support operating systems where ' and " get passed in program arguments
16    we check for them being first and last input character. If so we correct
17    input pointer and input length. Since now our scanner might not see a
18    terminating zero we change YYLIMIT again and drop the special zero rule.
19*/
20
21#include <stdlib.h>
22#include <stdio.h>
23#include <string.h>
24
25#define DEBUG(stmt) stmt
26
27int  stack[4];
28int  depth = 0;
29
30int push_num(const char *t, const char *l, int radix)
31{
32	int num = 0;
33
34	if (depth >= sizeof(stack))
35	{
36		return 3;
37	}
38
39	--t;
40	while(++t < l)
41	{
42		num = num * radix + (*t - '0');
43	}
44	DEBUG(printf("Num: %d\n", num));
45
46	stack[depth++] = num;
47	return 0;
48}
49
50int stack_add()
51{
52	if (depth < 2) return 4;
53
54	--depth;
55	stack[depth-1] = stack[depth-1] + stack[depth];
56	return 0;
57}
58
59int stack_sub()
60{
61	if (depth < 2) return 4;
62
63	--depth;
64	stack[depth-1] = stack[depth-1] - stack[depth];
65	return 0;
66}
67
68int scan(char *s, int l)
69{
70	char *p = s;
71	char *q = 0;
72	char *t;
73	int res = 0;
74
75#define YYCTYPE         char
76#define YYCURSOR        p
77#define YYLIMIT         (s+l+1)
78#define YYMARKER        q
79#define YYFILL(n)		{ return depth == 1 ? 0 : 2; }
80
81	while(!res)
82	{
83		t = p;
84/*!re2c
85	re2c:indent:top = 2;
86
87	DIGIT	= [0-9] ;
88	OCT		= "0" DIGIT+ ;
89	INT		= "0" | ( [1-9] DIGIT* ) ;
90	WS		= [ \t]+ ;
91
92	WS		{ continue; }
93	OCT		{ res = push_num(t, p, 8);	continue; }
94	INT		{ res = push_num(t, p, 10); continue; }
95	"+"		{ res = stack_add();		continue; }
96	"-"		{ res = stack_sub();		continue; }
97	[^]		{ res = 1; 					continue; }
98*/
99	}
100	return res;
101}
102
103int main(int argc, char **argv)
104{
105	if (argc > 1)
106	{
107		char *inp;
108		int res = 0, argp = 0, len;
109
110		while(!res && ++argp < argc)
111		{
112			inp = argv[argp];
113			len = strlen(inp);
114			if (inp[0] == '\"' && inp[len-1] == '\"')
115			{
116				++inp;
117				len -=2;
118			}
119			res = scan(inp, len);
120		}
121		switch(res)
122		{
123		case 0:
124			printf("Result: %d\n", stack[0]);
125			return 0;
126		case 1:
127			fprintf(stderr, "Illegal character in input.\n");
128			return 1;
129		case 2:
130			fprintf(stderr, "Premature end of input.\n");
131			return 2;
132		case 3:
133			fprintf(stderr, "Stack overflow.\n");
134			return 3;
135		case 4:
136			fprintf(stderr, "Stack underflow.\n");
137			return 4;
138		}
139	}
140	else
141	{
142		fprintf(stderr, "%s <expr>\n", argv[0]);
143		return 0;
144	}
145}
146