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