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