Mercurial > ~dholland > hg > ag > index.cgi
comparison tests/agcl/oldagsrc/rcalcx.syn @ 0:13d2b8934445
Import AnaGram (near-)release tree into Mercurial.
author | David A. Holland |
---|---|
date | Sat, 22 Dec 2007 17:52:45 -0500 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:13d2b8934445 |
---|---|
1 {/* | |
2 AnaGram, a System for Syntax Directed Parsing | |
3 RCALC.SYN: A Roman Numeral Calculator Example | |
4 | |
5 Copyright (c) MCMXCIII, MCMXCVI, Parsifal Software. | |
6 All Rights Reserved. | |
7 */} | |
8 | |
9 c = 'c' | |
10 d = 'd' | |
11 i = 'i' | |
12 l = 'l' | |
13 m = 'm' | |
14 v = 'v' | |
15 x = 'x' | |
16 | |
17 eof = 0 // Input is a string | |
18 | |
19 ws = ' ' + '\t' // Blanks and tabs | |
20 | |
21 [ | |
22 ~allow macros // Simplify debugging | |
23 disregard ws // Ignore blanks and tabs | |
24 lexeme { roman numeral} // No blanks inside a number | |
25 ~case sensitive // Allow upper/lower input | |
26 context type = int // Track context | |
27 default token type = long // All arithmetic uses longs | |
28 pointer input // Input is array in memory | |
29 reentrant parser | |
30 parser file name = "#.cpp" | |
31 ] | |
32 | |
33 | |
34 // Grammar definition | |
35 | |
36 (void) calculation $ | |
37 -> expression:x, eof =PCB.print_roman(x); | |
38 | |
39 | |
40 // Expression logic | |
41 | |
42 expression | |
43 -> term // Value of expression is value of term | |
44 -> expression:x, '+', term:y =x+y; | |
45 -> expression:x, '-', term:y =x-y; | |
46 | |
47 term | |
48 -> factor // Value of term is value of factor | |
49 -> term:x, '*', factor:y =x*y; | |
50 -> term:x, '/', factor:y =y ? x/y : PCB.divide_error(RULE_CONTEXT[2]); | |
51 | |
52 factor | |
53 -> roman numeral // Value of factor is value of roman numeral | |
54 -> "nihil" =0; | |
55 -> '(', expression:x, ')' =x; | |
56 -> '-', factor:x =-x; | |
57 | |
58 | |
59 // Roman Numeral Syntax | |
60 | |
61 roman numeral | |
62 -> thousands:x, hundreds:y =x+y; | |
63 -> thousands | |
64 -> hundreds // Value of roman numeral is value of hundreds | |
65 | |
66 thousands | |
67 -> m =1000; | |
68 -> thousands:x, m =x+1000; | |
69 | |
70 hundreds | |
71 -> hundreds field:x, tens:y =x+y; | |
72 -> hundreds field | |
73 -> tens // Value of hundreds is value of tens | |
74 | |
75 hundreds field | |
76 -> c, m =900; | |
77 -> c, d =400; | |
78 -> count hundreds | |
79 | |
80 count hundreds | |
81 -> c =100; | |
82 -> d =500; | |
83 -> count hundreds:x, c =x+100; | |
84 | |
85 tens | |
86 -> tens field:x, units:y =x+y; | |
87 -> tens field | |
88 -> units // Value of tens is value of units | |
89 | |
90 tens field | |
91 -> x, m =990; | |
92 -> x, d =490; | |
93 -> x, c =90; | |
94 -> x, l =40; | |
95 -> count tens | |
96 | |
97 count tens | |
98 -> x =10; | |
99 -> l =50; | |
100 -> count tens:x, x =x+10; | |
101 | |
102 units | |
103 -> i, m =999; | |
104 -> i, d =499; | |
105 -> i, c =99; | |
106 -> i, l =49; | |
107 -> i, x =9; | |
108 -> i, v =4; | |
109 -> count units // Value of "units" is value of "count units" | |
110 | |
111 count units | |
112 -> i =1; | |
113 -> v =5; | |
114 -> count units:x, i =x+1; | |
115 | |
116 | |
117 { /* Embedded C */ | |
118 #include <stdio.h> | |
119 | |
120 #define PCB_TYPE Parser | |
121 | |
122 class Parser : public rcalcx_pcb_type { | |
123 int semantic_error; | |
124 public: | |
125 Parser() {} | |
126 void parse(char *); | |
127 void syntax_error(); | |
128 int divide_error(int cn); | |
129 void print_roman(long k); | |
130 }; | |
131 | |
132 | |
133 void Parser::parse(char *text) { | |
134 pointer = (unsigned char *) text; | |
135 semantic_error = 0; | |
136 rcalcx(this); | |
137 } | |
138 | |
139 /* Macro Definitions */ | |
140 | |
141 #define GET_CONTEXT CONTEXT = PCB.column | |
142 #define SYNTAX_ERROR PCB.syntax_error() | |
143 | |
144 /* | |
145 | |
146 syntax_error() positions a '^' character under the input line at the | |
147 point where the syntax error was discovered and then writes the error | |
148 message. | |
149 | |
150 */ | |
151 | |
152 void Parser::syntax_error() { | |
153 int k = column; | |
154 while (k-- > 0) putchar(' '); | |
155 printf("^? %s\n","ERRARE HUMANUM EST\n"); | |
156 } | |
157 | |
158 | |
159 /* | |
160 | |
161 divide_error() is called when an attempt is made to divide by zero. The | |
162 entire divisor is marked with '^' characters. "semantic_error" is set | |
163 in order to disable printing of a result. | |
164 | |
165 */ | |
166 | |
167 int Parser::divide_error(int cn) { | |
168 int k = column - cn; | |
169 while (cn--) putchar(' '); | |
170 while (k--) putchar('^'); | |
171 puts(" DIVISOR NIHIL EST"); | |
172 semantic_error = 1; | |
173 return 0; | |
174 } | |
175 | |
176 | |
177 /* | |
178 | |
179 print_roman() prints a signed integer in upper case Roman numerals. | |
180 | |
181 */ | |
182 | |
183 void Parser::print_roman(long k) { | |
184 if (semantic_error) { | |
185 semantic_error = 0; | |
186 return; | |
187 } | |
188 printf(" = "); | |
189 if (k == 0) {printf("NIHIL\n"); return;} | |
190 | |
191 if (k < 0) putchar('-'), k=-k; | |
192 | |
193 while (k >= 1000) putchar('M'), k-=1000; | |
194 | |
195 if (k >= 900) printf("CM"), k-=900; | |
196 if (k >= 500) putchar('D'), k-=500; | |
197 if (k >= 400) printf("CD"), k-=400; | |
198 | |
199 while (k >= 100) putchar('C'), k-=100; | |
200 | |
201 if (k >= 90) printf("XC"), k-=90; | |
202 if (k >= 50) putchar('L'), k-=50; | |
203 if (k >= 40) printf("XL"), k-=40; | |
204 | |
205 while (k >= 10) putchar('X'), k-=10; | |
206 | |
207 if (k >= 9) printf("IX"), k -= 9; | |
208 if (k >= 5) putchar('V'), k-=5; | |
209 if (k >= 4) printf("IV"), k-=4; | |
210 | |
211 while (k >= 1) putchar('I'), k--; | |
212 | |
213 putchar('\n'); | |
214 } | |
215 | |
216 | |
217 /* Main Program -- reads a line from stdin and calls parser */ | |
218 | |
219 int main(void) { | |
220 char line[82]; | |
221 while (1) { | |
222 Parser pcb; | |
223 printf("#"); | |
224 if (gets(line) == NULL) break; | |
225 pcb.parse(line); | |
226 } | |
227 return 0; | |
228 } | |
229 | |
230 } // End of Embedded C |