Mercurial > ~dholland > hg > ag > index.cgi
comparison tests/agcl/oldagsrc/rcalc.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 =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 : divide_error(pcb_pointer, 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 | |
121 /* Macro Definitions */ | |
122 | |
123 #define GET_CONTEXT CONTEXT = PCB.column | |
124 #define SYNTAX_ERROR syntax_error(pcb_pointer) | |
125 | |
126 int semantic_error = 0; /* Divide by zero flag */ | |
127 | |
128 | |
129 /* | |
130 | |
131 syntax_error() positions a '^' character under the input line at the | |
132 point where the syntax error was discovered and then writes the error | |
133 message. | |
134 | |
135 */ | |
136 | |
137 void syntax_error(PCB_DECL) { | |
138 int k = PCB.column; | |
139 while (k-- > 0) putchar(' '); | |
140 printf("^? %s\n","ERRARE HUMANUM EST\n"); | |
141 } | |
142 | |
143 | |
144 /* | |
145 | |
146 divide_error() is called when an attempt is made to divide by zero. The | |
147 entire divisor is marked with '^' characters. "semantic_error" is set | |
148 in order to disable printing of a result. | |
149 | |
150 */ | |
151 | |
152 int divide_error(PCB_DECL, int cn) { | |
153 int k = PCB.column - cn; | |
154 while (cn--) putchar(' '); | |
155 while (k--) putchar('^'); | |
156 puts(" DIVISOR NIHIL EST"); | |
157 semantic_error = 1; | |
158 return 0; | |
159 } | |
160 | |
161 | |
162 /* | |
163 | |
164 print_roman() prints a signed integer in upper case Roman numerals. | |
165 | |
166 */ | |
167 | |
168 void print_roman(long k) { | |
169 if (semantic_error) { | |
170 semantic_error = 0; | |
171 return; | |
172 } | |
173 printf(" = "); | |
174 if (k == 0) {printf("NIHIL\n"); return;} | |
175 | |
176 if (k < 0) putchar('-'), k=-k; | |
177 | |
178 while (k >= 1000) putchar('M'), k-=1000; | |
179 | |
180 if (k >= 900) printf("CM"), k-=900; | |
181 if (k >= 500) putchar('D'), k-=500; | |
182 if (k >= 400) printf("CD"), k-=400; | |
183 | |
184 while (k >= 100) putchar('C'), k-=100; | |
185 | |
186 if (k >= 90) printf("XC"), k-=90; | |
187 if (k >= 50) putchar('L'), k-=50; | |
188 if (k >= 40) printf("XL"), k-=40; | |
189 | |
190 while (k >= 10) putchar('X'), k-=10; | |
191 | |
192 if (k >= 9) printf("IX"), k -= 9; | |
193 if (k >= 5) putchar('V'), k-=5; | |
194 if (k >= 4) printf("IV"), k-=4; | |
195 | |
196 while (k >= 1) putchar('I'), k--; | |
197 | |
198 putchar('\n'); | |
199 } | |
200 | |
201 | |
202 /* Main Program -- reads a line from stdin and calls parser */ | |
203 | |
204 int main(void) { | |
205 char line[82]; | |
206 while (1) { | |
207 PCB_TYPE pcb; | |
208 printf("#"); | |
209 if (gets(line) == NULL) break; | |
210 pcb.pointer = (unsigned char *) line; | |
211 rcalc(&pcb); | |
212 } | |
213 return 0; | |
214 } | |
215 | |
216 } // End of Embedded C |