Mercurial > ~dholland > hg > ag > index.cgi
comparison examples/rcalc/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 MCMXCIII, MCMXCVI, Parsifal Software. All Rights Reserved. | |
6 * Copyright MMVII David A. Holland. All Rights Reserved. | |
7 * | |
8 * This software is provided 'as-is', without any express or implied | |
9 * warranty. In no event will the authors be held liable for any damages | |
10 * arising from the use of this software. | |
11 * | |
12 * Permission is granted to anyone to use this software for any purpose, | |
13 * including commercial applications, and to alter it and redistribute it | |
14 * freely, subject to the following restrictions: | |
15 * | |
16 * 1. The origin of this software must not be misrepresented; you must not | |
17 * claim that you wrote the original software. If you use this software | |
18 * in a product, an acknowledgment in the product documentation would be | |
19 * appreciated but is not required. | |
20 * 2. Altered source versions must be plainly marked as such, and must not be | |
21 * misrepresented as being the original software. | |
22 * 3. This notice may not be removed or altered from any source distribution. | |
23 */} | |
24 | |
25 c = 'c' | |
26 d = 'd' | |
27 i = 'i' | |
28 l = 'l' | |
29 m = 'm' | |
30 v = 'v' | |
31 x = 'x' | |
32 | |
33 eof = 0 + '\n' // Input is a one-line string | |
34 | |
35 ws = ' ' + '\t' + '\r' // Blanks, tabs, and stray CRs | |
36 | |
37 [ | |
38 ~allow macros // Simplify debugging | |
39 disregard ws // Ignore blanks and tabs | |
40 lexeme { roman numeral} // No blanks inside a number | |
41 ~case sensitive // Allow upper/lower input | |
42 context type = int // Track context | |
43 default token type = long // All arithmetic uses longs | |
44 pointer input // Input is array in memory | |
45 ] | |
46 | |
47 | |
48 // Grammar definition | |
49 | |
50 (void) calculation $ | |
51 -> expression:x, eof =print_roman(x); | |
52 | |
53 | |
54 // Expression logic | |
55 | |
56 expression | |
57 -> term // Value of expression is value of term | |
58 -> expression:x, '+', term:y =x+y; | |
59 -> expression:x, '-', term:y =x-y; | |
60 | |
61 term | |
62 -> factor // Value of term is value of factor | |
63 -> term:x, '*', factor:y =x*y; | |
64 -> term:x, '/', factor:y =y ? x/y : divide_error(RULE_CONTEXT[2]); | |
65 | |
66 factor | |
67 -> roman numeral // Value of factor is value of roman numeral | |
68 -> "nihil" =0; | |
69 -> '(', expression:x, ')' =x; | |
70 -> '-', factor:x =-x; | |
71 | |
72 | |
73 // Roman Numeral Syntax | |
74 | |
75 roman numeral | |
76 -> thousands:x, hundreds?:y =x+y; | |
77 -> hundreds // Value of roman numeral is value of hundreds | |
78 | |
79 thousands | |
80 -> m =1000; | |
81 -> thousands:x, m =x+1000; | |
82 | |
83 hundreds | |
84 -> hundreds field:x, tens?:y =x+y; | |
85 -> tens // Value of hundreds is value of tens | |
86 | |
87 hundreds field | |
88 -> c, m =900; | |
89 -> c, d =400; | |
90 -> count hundreds | |
91 | |
92 count hundreds | |
93 -> c =100; | |
94 -> d =500; | |
95 -> count hundreds:x, c =x+100; | |
96 | |
97 tens | |
98 -> tens field:x, units?:y =x+y; | |
99 -> units // Value of tens is value of units | |
100 | |
101 tens field | |
102 -> x, m =990; | |
103 -> x, d =490; | |
104 -> x, c =90; | |
105 -> x, l =40; | |
106 -> count tens | |
107 | |
108 count tens | |
109 -> x =10; | |
110 -> l =50; | |
111 -> count tens:x, x =x+10; | |
112 | |
113 units | |
114 -> i, m =999; | |
115 -> i, d =499; | |
116 -> i, c =99; | |
117 -> i, l =49; | |
118 -> i, x =9; | |
119 -> i, v =4; | |
120 -> count units // Value of "units" is value of "count units" | |
121 | |
122 count units | |
123 -> i =1; | |
124 -> v =5; | |
125 -> count units:x, i =x+1; | |
126 | |
127 | |
128 { /* Embedded C */ | |
129 #include <stdio.h> | |
130 | |
131 | |
132 /* Macro Definitions */ | |
133 | |
134 #define GET_CONTEXT CONTEXT = PCB.column | |
135 #define SYNTAX_ERROR syntax_error() | |
136 | |
137 int semantic_error = 0; /* Divide by zero flag */ | |
138 | |
139 | |
140 /* | |
141 | |
142 syntax_error() positions a '^' character under the input line at the | |
143 point where the syntax error was discovered and then writes the error | |
144 message. | |
145 | |
146 */ | |
147 | |
148 void syntax_error(void) { | |
149 int k = PCB.column; | |
150 while (k-- > 0) putchar(' '); | |
151 printf("^? %s\n","ERRARE HUMANUM EST\n"); | |
152 } | |
153 | |
154 | |
155 /* | |
156 | |
157 divide_error() is called when an attempt is made to divide by zero. The | |
158 entire divisor is marked with '^' characters. "semantic_error" is set | |
159 in order to disable printing of a result. | |
160 | |
161 */ | |
162 | |
163 int divide_error(int cn) { | |
164 int k = PCB.column - cn; | |
165 while (cn--) putchar(' '); | |
166 while (k--) putchar('^'); | |
167 puts(" DIVISOR NIHIL EST"); | |
168 semantic_error = 1; | |
169 return 0; | |
170 } | |
171 | |
172 | |
173 /* | |
174 | |
175 print_roman() prints a signed integer in upper case Roman numerals. | |
176 | |
177 */ | |
178 | |
179 void print_roman(long k) { | |
180 if (semantic_error) { | |
181 semantic_error = 0; | |
182 return; | |
183 } | |
184 printf(" = "); | |
185 if (k == 0) {printf("NIHIL\n"); return;} | |
186 | |
187 if (k < 0) putchar('-'), k=-k; | |
188 | |
189 while (k >= 1000) putchar('M'), k-=1000; | |
190 | |
191 if (k >= 900) printf("CM"), k-=900; | |
192 if (k >= 500) putchar('D'), k-=500; | |
193 if (k >= 400) printf("CD"), k-=400; | |
194 | |
195 while (k >= 100) putchar('C'), k-=100; | |
196 | |
197 if (k >= 90) printf("XC"), k-=90; | |
198 if (k >= 50) putchar('L'), k-=50; | |
199 if (k >= 40) printf("XL"), k-=40; | |
200 | |
201 while (k >= 10) putchar('X'), k-=10; | |
202 | |
203 if (k >= 9) printf("IX"), k -= 9; | |
204 if (k >= 5) putchar('V'), k-=5; | |
205 if (k >= 4) printf("IV"), k-=4; | |
206 | |
207 while (k >= 1) putchar('I'), k--; | |
208 | |
209 putchar('\n'); | |
210 } | |
211 | |
212 | |
213 /* Main Program -- reads a line from stdin and calls parser */ | |
214 | |
215 int main(void) { | |
216 char line[1024]; | |
217 while (1) { | |
218 printf("#"); | |
219 fflush(stdout); | |
220 if (fgets(line, sizeof(line), stdin) == NULL) break; | |
221 rcalc_pcb.pointer = (unsigned char *) line; | |
222 rcalc(); | |
223 } | |
224 return 0; | |
225 } | |
226 | |
227 } // End of Embedded C |