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