Mercurial > ~dholland > hg > ag > index.cgi
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/agcl/parsifal/ss-sscx.syn Sat Dec 22 17:52:45 2007 -0500 @@ -0,0 +1,292 @@ +{/* + Copyright 1992, Jerome T. Holland + See the file COPYING for license and usage terms. + + An example syntax and supporting classes for implementing a spreadsheet + + Class definitions are found in sscxdefs.h + + This example is largely intended to serve as an illustration, and is + incomplete in a number of ways. In particular, the expression syntax + is that of C, except for identifiers, and only a few functions are + implemented. More may be implemented trivially by following the + patterns provided. + + The supported operations are: + Conditional expressions: ? : + Logical operators: !, &, | + Comparison operators: ==, !=, <, <=, >, >= + Binary arithmetic operators: +, -, *, / + Exponentiation: ** + Unary arithmetic operators: +, - + Parentheses + Function calls abs, sin, asin, atan + + A note on the technique used for compilation: + + The basic approach is to build a Reverse Polish Notation stack. + During parsing, the constants, cell locators, and operators are + stacked on separate temporary stacks. When parsing is complete, + these stacks are unloaded into arrays belonging to the cell + expression object. Note that there is a one to one correspondence + between items on the constant stack and fd (fetch double) operators + in the op stack. Since there are no branching instructions, there + there is one and ony one constant corresponding to a fd operation + so it is sufficient to simply increment an index into the constant + array as execution progresses, to know which constant to use. The + same logic holds for cell locators. +*/ + +#include <math.h> +#include "agstk.h" +#include <string.h> +#include <errno.h> +#include "sscxdefs.h" + +} + +// -- CONFIGURATION SECTION ---------------------------- +[ + disregard white space + lexeme {real, cell name} + pointer input + parser name = parseKernel + parser file name = "#.cpp" + line numbers // For debugging + escape backslashes // Comment this line if using a Borland compiler +] + +input string $ // specify grammar token + -> expression, eof + +expression + -> logical or expression + -> logical or expression, '?', + expression, ':', expression =opStack.push(CellExpression::cond); + +logical or expression + -> logical and expression + -> logical or expression, '|', logical and expression =opStack.push(CellExpression::or); + +logical and expression + -> equality expression + -> logical and expression, '&', equality expression =opStack.push(CellExpression::and); + +equality expression + -> relational expression + -> equality expression:x, "==", relational expression:y =opStack.push(CellExpression::eq); + -> equality expression:x, "!=", relational expression:y =opStack.push(CellExpression::ne); + +relational expression + -> additive expression + -> relational expression, '<', additive expression =opStack.push(CellExpression::lt); + -> relational expression, "<=", additive expression =opStack.push(CellExpression::le); + -> relational expression, '>', additive expression =opStack.push(CellExpression::gt); + -> relational expression, ">=", additive expression =opStack.push(CellExpression::ge); + +additive expression + -> multiplicative expression + -> additive expression, '+', multiplicative expression =opStack.push(CellExpression::add); + -> additive expression, '-', multiplicative expression =opStack.push(CellExpression::sub); + +multiplicative expression + -> factor + -> multiplicative expression:x, '*', factor:y =opStack.push(CellExpression::mpy); + -> multiplicative expression:x, '/', factor:y =opStack.push(CellExpression::div); + +factor + -> primary + -> primary, "**", factor =opStack.push(CellExpression::pow); + +primary + -> real:x =doubleStack.push(x), opStack.push(CellExpression::fd); + -> cell name:n =locatorStack.push(n), opStack.push(CellExpression::fc); + -> "abs", '(', expression, ')' =opStack.push(CellExpression::abs); + -> "sin", '(', expression, ')' =opStack.push(CellExpression::sin); + -> "asin", '(', expression, ')' =opStack.push(CellExpression::sin); + -> "atan", '(', expression, ')' =opStack.push(CellExpression::atan); + -> "atan", '(', expression, ',', expression, ')' =opStack.push(CellExpression::atan2); + -> '(', expression, ')' + -> '-', primary =opStack.push(CellExpression::minus); + -> '+', primary + -> '!', primary =opStack.push(CellExpression::not); + +// -- LEXICAL UNITS ------------------------------------------------ +digit = '0-9' +eof = 0 + +(void) white space + -> ' ' + '\t' + '\f' + '\v' + '\r' + '\n' + -> "/*", ~eof?..., "*/" // C style comment + -> "//", ~(eof+'\n')?..., '\n' // C++ style comment + +(double) real + -> simple real + -> simple real:x, 'e'+'E', '+'?,exponent:e =x*pow(10,e); + -> simple real:x, 'e'+'E', '-',exponent:e =x*pow(10,-e); + +(double) simple real + -> integer part:i, '.', fraction part:f = i+f; + -> integer part, '.'? + -> '.', fraction part:f = f; + +(double) integer part + -> digit:d = d-'0'; + -> integer part:x, digit:d = 10*x + d-'0'; + +(double) fraction part + -> digit:d =(d-'0')/10.; + -> digit:d, fraction part:f =(d-'0' + f)/10.; + +(int) exponent + -> digit:d = d-'0'; + -> exponent:x, digit:d = 10*x + d-'0'; + +(Locator) cell name //value of name token is length of name string + -> column:c, row:r =Locator(r-1,c); + -> '$',column:c, row:r =Locator(r-1,c).setAbsoluteCol(); + -> column:c, '$', row:r =Locator(r-1,c).setAbsoluteRow(); + -> '$', column:c, '$', row:r =Locator(r-1,c).setAbsoluteRow().setAbsoluteCol(); + +(int) letter + -> 'a-z':c =c - 'a'; + -> 'A-Z':c =c = 'A'; + +(int) column + -> letter:n =n; + -> column:c, letter:n =26*c + n; + +(int) row + -> digit:d =d - '0'; + -> row:n, digit:d =10*n + d - '0'; + +{ + +// Stacks for use in parsing and compiling + +AgStack<double> doubleStack; +AgStack<Locator> locatorStack; +AgStack<CellExpression::Op> opStack; + +// Data for a simple minded test + +CellExpression *Locator::expression[3][3]; +int Locator::maxRow = 3; +int Locator::maxCol = 3; + +char *expressionText[3][3] = { + {"17", "19", "-23"}, + {"2*a1", "b1 - a2", "a2+b2"}, + {"b2 + c2", "a3-a2", "a2/b2"} +}; + +/* + Constructor for CellExpression + + Parses the input text and creates byte code for later execution by + the value() function. +*/ + +CellExpression::CellExpression(char *text) + : constant(0), nConstants(0), + locator(0), nLocators(0), + op(0), nOps(0), + errorFlag(0), busy(0), cycle(0) +{ + doubleStack.reset(); + locatorStack.reset(); + opStack.reset(); + PCB.pointer = (unsigned char *) text; + parseKernel(); // Parse expression + if (PCB.exit_flag != AG_SUCCESS_CODE) {errorFlag = 1; return;} + // save parse results + nConstants = doubleStack.size(); + nLocators = locatorStack.size(); + nOps = opStack.size(); + constant = new double[nConstants]; + locator = new Locator[nLocators]; + op = new Op[nOps]; + int i; + for (i = nConstants; i--;) constant[i] = doubleStack.pop(); + for (i = nLocators; i--;) locator[i] = locatorStack.pop(); + for (i = nOps; i--;) op[i] = opStack.pop(); +} + +// Function to execute byte code + +Number CellExpression::value() { + if (errorFlag) return Number(); + if (busy) { // Check for cyclic definition + errorFlag = cycle = 1; + return Number(); + } + busy = 1; + int constantIndex = 0; + int locatorIndex = 0; + + AgStack<Number> stack; // Arithmetic stack for byte code interpreter + + Number temp; // temporary variable + int pc = 0; + while (pc < nOps && errorFlag == 0) { + switch (op[pc]) { + case add: stack.pop(temp); stack.top() += temp; break; + case sub: stack.pop(temp); stack.top() -= temp; break; + case mpy: stack.pop(temp); stack.top() *= temp; break; + case div: stack.pop(temp); stack.top() /= temp; break; + case pow: stack.pop(temp); stack.top() = stack.top().pow(temp); break; + case lt: stack.pop(temp); stack.top() = stack.top() < temp; break; + case le: stack.pop(temp); stack.top() = stack.top() <= temp; break; + case gt: stack.pop(temp); stack.top() = stack.top() > temp; break; + case ge: stack.pop(temp); stack.top() = stack.top() >= temp; break; + case eq: stack.pop(temp); stack.top() = stack.top() == temp; break; + case ne: stack.pop(temp); stack.top() = stack.top() != temp; break; + case and: stack.pop(temp); stack.top() = stack.top() != Number(0) & temp != Number(0); break; + case or: stack.pop(temp); stack.top() = stack.top() != Number(0) | temp != Number(0); break; + case minus: stack.top() = -stack.top(); break; + case not: stack.top() = stack.top() == Number(0); break; + case cond: { + Number secondOption = stack.pop(); + Number firstOption = stack.pop(); + if (stack.top().bad) break; + stack.top() = (stack.top() != Number(0)) ? firstOption : secondOption; + break; + } + case abs: stack.top() = stack.top().abs(); break; + case sin: stack.top() = stack.top().sin(); break; + case asin: stack.top() = stack.top().asin(); break; + case atan: stack.top() = stack.top().atan(); break; + case atan2: temp = stack.pop(); stack.top() = stack.top().atan2(temp); break; +// Fetch double + case fd: stack.push(constant[constantIndex++]); break; +// Fetch cell value + case fc: { + CellExpression *x = locator[locatorIndex++].cellExpression(); + Number temp; + if (x != 0) temp = x->value(); + stack.push(temp); + break; + } + } + pc++; + } + busy = 0; + return stack.top(); +} + +// Rather trivial test + +int main() { + int i, j; +// Initialize CellExpresions + for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) { + Locator::expression[i][j] = new CellExpression(expressionText[i][j]); + } +// Calculate and print out values + for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) { + printf("cell[%d][%d] = %G\n", i, j, (double) (Locator::expression[i][j]->value())); + } + return 0; +} + +}