Mercurial > ~dholland > hg > ag > index.cgi
comparison tests/agcl/parsifal/ss-sscx.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 Copyright 1992, Jerome T. Holland | |
3 See the file COPYING for license and usage terms. | |
4 | |
5 An example syntax and supporting classes for implementing a spreadsheet | |
6 | |
7 Class definitions are found in sscxdefs.h | |
8 | |
9 This example is largely intended to serve as an illustration, and is | |
10 incomplete in a number of ways. In particular, the expression syntax | |
11 is that of C, except for identifiers, and only a few functions are | |
12 implemented. More may be implemented trivially by following the | |
13 patterns provided. | |
14 | |
15 The supported operations are: | |
16 Conditional expressions: ? : | |
17 Logical operators: !, &, | | |
18 Comparison operators: ==, !=, <, <=, >, >= | |
19 Binary arithmetic operators: +, -, *, / | |
20 Exponentiation: ** | |
21 Unary arithmetic operators: +, - | |
22 Parentheses | |
23 Function calls abs, sin, asin, atan | |
24 | |
25 A note on the technique used for compilation: | |
26 | |
27 The basic approach is to build a Reverse Polish Notation stack. | |
28 During parsing, the constants, cell locators, and operators are | |
29 stacked on separate temporary stacks. When parsing is complete, | |
30 these stacks are unloaded into arrays belonging to the cell | |
31 expression object. Note that there is a one to one correspondence | |
32 between items on the constant stack and fd (fetch double) operators | |
33 in the op stack. Since there are no branching instructions, there | |
34 there is one and ony one constant corresponding to a fd operation | |
35 so it is sufficient to simply increment an index into the constant | |
36 array as execution progresses, to know which constant to use. The | |
37 same logic holds for cell locators. | |
38 */ | |
39 | |
40 #include <math.h> | |
41 #include "agstk.h" | |
42 #include <string.h> | |
43 #include <errno.h> | |
44 #include "sscxdefs.h" | |
45 | |
46 } | |
47 | |
48 // -- CONFIGURATION SECTION ---------------------------- | |
49 [ | |
50 disregard white space | |
51 lexeme {real, cell name} | |
52 pointer input | |
53 parser name = parseKernel | |
54 parser file name = "#.cpp" | |
55 line numbers // For debugging | |
56 escape backslashes // Comment this line if using a Borland compiler | |
57 ] | |
58 | |
59 input string $ // specify grammar token | |
60 -> expression, eof | |
61 | |
62 expression | |
63 -> logical or expression | |
64 -> logical or expression, '?', | |
65 expression, ':', expression =opStack.push(CellExpression::cond); | |
66 | |
67 logical or expression | |
68 -> logical and expression | |
69 -> logical or expression, '|', logical and expression =opStack.push(CellExpression::or); | |
70 | |
71 logical and expression | |
72 -> equality expression | |
73 -> logical and expression, '&', equality expression =opStack.push(CellExpression::and); | |
74 | |
75 equality expression | |
76 -> relational expression | |
77 -> equality expression:x, "==", relational expression:y =opStack.push(CellExpression::eq); | |
78 -> equality expression:x, "!=", relational expression:y =opStack.push(CellExpression::ne); | |
79 | |
80 relational expression | |
81 -> additive expression | |
82 -> relational expression, '<', additive expression =opStack.push(CellExpression::lt); | |
83 -> relational expression, "<=", additive expression =opStack.push(CellExpression::le); | |
84 -> relational expression, '>', additive expression =opStack.push(CellExpression::gt); | |
85 -> relational expression, ">=", additive expression =opStack.push(CellExpression::ge); | |
86 | |
87 additive expression | |
88 -> multiplicative expression | |
89 -> additive expression, '+', multiplicative expression =opStack.push(CellExpression::add); | |
90 -> additive expression, '-', multiplicative expression =opStack.push(CellExpression::sub); | |
91 | |
92 multiplicative expression | |
93 -> factor | |
94 -> multiplicative expression:x, '*', factor:y =opStack.push(CellExpression::mpy); | |
95 -> multiplicative expression:x, '/', factor:y =opStack.push(CellExpression::div); | |
96 | |
97 factor | |
98 -> primary | |
99 -> primary, "**", factor =opStack.push(CellExpression::pow); | |
100 | |
101 primary | |
102 -> real:x =doubleStack.push(x), opStack.push(CellExpression::fd); | |
103 -> cell name:n =locatorStack.push(n), opStack.push(CellExpression::fc); | |
104 -> "abs", '(', expression, ')' =opStack.push(CellExpression::abs); | |
105 -> "sin", '(', expression, ')' =opStack.push(CellExpression::sin); | |
106 -> "asin", '(', expression, ')' =opStack.push(CellExpression::sin); | |
107 -> "atan", '(', expression, ')' =opStack.push(CellExpression::atan); | |
108 -> "atan", '(', expression, ',', expression, ')' =opStack.push(CellExpression::atan2); | |
109 -> '(', expression, ')' | |
110 -> '-', primary =opStack.push(CellExpression::minus); | |
111 -> '+', primary | |
112 -> '!', primary =opStack.push(CellExpression::not); | |
113 | |
114 // -- LEXICAL UNITS ------------------------------------------------ | |
115 digit = '0-9' | |
116 eof = 0 | |
117 | |
118 (void) white space | |
119 -> ' ' + '\t' + '\f' + '\v' + '\r' + '\n' | |
120 -> "/*", ~eof?..., "*/" // C style comment | |
121 -> "//", ~(eof+'\n')?..., '\n' // C++ style comment | |
122 | |
123 (double) real | |
124 -> simple real | |
125 -> simple real:x, 'e'+'E', '+'?,exponent:e =x*pow(10,e); | |
126 -> simple real:x, 'e'+'E', '-',exponent:e =x*pow(10,-e); | |
127 | |
128 (double) simple real | |
129 -> integer part:i, '.', fraction part:f = i+f; | |
130 -> integer part, '.'? | |
131 -> '.', fraction part:f = f; | |
132 | |
133 (double) integer part | |
134 -> digit:d = d-'0'; | |
135 -> integer part:x, digit:d = 10*x + d-'0'; | |
136 | |
137 (double) fraction part | |
138 -> digit:d =(d-'0')/10.; | |
139 -> digit:d, fraction part:f =(d-'0' + f)/10.; | |
140 | |
141 (int) exponent | |
142 -> digit:d = d-'0'; | |
143 -> exponent:x, digit:d = 10*x + d-'0'; | |
144 | |
145 (Locator) cell name //value of name token is length of name string | |
146 -> column:c, row:r =Locator(r-1,c); | |
147 -> '$',column:c, row:r =Locator(r-1,c).setAbsoluteCol(); | |
148 -> column:c, '$', row:r =Locator(r-1,c).setAbsoluteRow(); | |
149 -> '$', column:c, '$', row:r =Locator(r-1,c).setAbsoluteRow().setAbsoluteCol(); | |
150 | |
151 (int) letter | |
152 -> 'a-z':c =c - 'a'; | |
153 -> 'A-Z':c =c = 'A'; | |
154 | |
155 (int) column | |
156 -> letter:n =n; | |
157 -> column:c, letter:n =26*c + n; | |
158 | |
159 (int) row | |
160 -> digit:d =d - '0'; | |
161 -> row:n, digit:d =10*n + d - '0'; | |
162 | |
163 { | |
164 | |
165 // Stacks for use in parsing and compiling | |
166 | |
167 AgStack<double> doubleStack; | |
168 AgStack<Locator> locatorStack; | |
169 AgStack<CellExpression::Op> opStack; | |
170 | |
171 // Data for a simple minded test | |
172 | |
173 CellExpression *Locator::expression[3][3]; | |
174 int Locator::maxRow = 3; | |
175 int Locator::maxCol = 3; | |
176 | |
177 char *expressionText[3][3] = { | |
178 {"17", "19", "-23"}, | |
179 {"2*a1", "b1 - a2", "a2+b2"}, | |
180 {"b2 + c2", "a3-a2", "a2/b2"} | |
181 }; | |
182 | |
183 /* | |
184 Constructor for CellExpression | |
185 | |
186 Parses the input text and creates byte code for later execution by | |
187 the value() function. | |
188 */ | |
189 | |
190 CellExpression::CellExpression(char *text) | |
191 : constant(0), nConstants(0), | |
192 locator(0), nLocators(0), | |
193 op(0), nOps(0), | |
194 errorFlag(0), busy(0), cycle(0) | |
195 { | |
196 doubleStack.reset(); | |
197 locatorStack.reset(); | |
198 opStack.reset(); | |
199 PCB.pointer = (unsigned char *) text; | |
200 parseKernel(); // Parse expression | |
201 if (PCB.exit_flag != AG_SUCCESS_CODE) {errorFlag = 1; return;} | |
202 // save parse results | |
203 nConstants = doubleStack.size(); | |
204 nLocators = locatorStack.size(); | |
205 nOps = opStack.size(); | |
206 constant = new double[nConstants]; | |
207 locator = new Locator[nLocators]; | |
208 op = new Op[nOps]; | |
209 int i; | |
210 for (i = nConstants; i--;) constant[i] = doubleStack.pop(); | |
211 for (i = nLocators; i--;) locator[i] = locatorStack.pop(); | |
212 for (i = nOps; i--;) op[i] = opStack.pop(); | |
213 } | |
214 | |
215 // Function to execute byte code | |
216 | |
217 Number CellExpression::value() { | |
218 if (errorFlag) return Number(); | |
219 if (busy) { // Check for cyclic definition | |
220 errorFlag = cycle = 1; | |
221 return Number(); | |
222 } | |
223 busy = 1; | |
224 int constantIndex = 0; | |
225 int locatorIndex = 0; | |
226 | |
227 AgStack<Number> stack; // Arithmetic stack for byte code interpreter | |
228 | |
229 Number temp; // temporary variable | |
230 int pc = 0; | |
231 while (pc < nOps && errorFlag == 0) { | |
232 switch (op[pc]) { | |
233 case add: stack.pop(temp); stack.top() += temp; break; | |
234 case sub: stack.pop(temp); stack.top() -= temp; break; | |
235 case mpy: stack.pop(temp); stack.top() *= temp; break; | |
236 case div: stack.pop(temp); stack.top() /= temp; break; | |
237 case pow: stack.pop(temp); stack.top() = stack.top().pow(temp); break; | |
238 case lt: stack.pop(temp); stack.top() = stack.top() < temp; break; | |
239 case le: stack.pop(temp); stack.top() = stack.top() <= temp; break; | |
240 case gt: stack.pop(temp); stack.top() = stack.top() > temp; break; | |
241 case ge: stack.pop(temp); stack.top() = stack.top() >= temp; break; | |
242 case eq: stack.pop(temp); stack.top() = stack.top() == temp; break; | |
243 case ne: stack.pop(temp); stack.top() = stack.top() != temp; break; | |
244 case and: stack.pop(temp); stack.top() = stack.top() != Number(0) & temp != Number(0); break; | |
245 case or: stack.pop(temp); stack.top() = stack.top() != Number(0) | temp != Number(0); break; | |
246 case minus: stack.top() = -stack.top(); break; | |
247 case not: stack.top() = stack.top() == Number(0); break; | |
248 case cond: { | |
249 Number secondOption = stack.pop(); | |
250 Number firstOption = stack.pop(); | |
251 if (stack.top().bad) break; | |
252 stack.top() = (stack.top() != Number(0)) ? firstOption : secondOption; | |
253 break; | |
254 } | |
255 case abs: stack.top() = stack.top().abs(); break; | |
256 case sin: stack.top() = stack.top().sin(); break; | |
257 case asin: stack.top() = stack.top().asin(); break; | |
258 case atan: stack.top() = stack.top().atan(); break; | |
259 case atan2: temp = stack.pop(); stack.top() = stack.top().atan2(temp); break; | |
260 // Fetch double | |
261 case fd: stack.push(constant[constantIndex++]); break; | |
262 // Fetch cell value | |
263 case fc: { | |
264 CellExpression *x = locator[locatorIndex++].cellExpression(); | |
265 Number temp; | |
266 if (x != 0) temp = x->value(); | |
267 stack.push(temp); | |
268 break; | |
269 } | |
270 } | |
271 pc++; | |
272 } | |
273 busy = 0; | |
274 return stack.top(); | |
275 } | |
276 | |
277 // Rather trivial test | |
278 | |
279 int main() { | |
280 int i, j; | |
281 // Initialize CellExpresions | |
282 for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) { | |
283 Locator::expression[i][j] = new CellExpression(expressionText[i][j]); | |
284 } | |
285 // Calculate and print out values | |
286 for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) { | |
287 printf("cell[%d][%d] = %G\n", i, j, (double) (Locator::expression[i][j]->value())); | |
288 } | |
289 return 0; | |
290 } | |
291 | |
292 } |