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;
+}
+
+}