view tests/agcl/parsifal/ss-fp.syn @ 2:4b08ee1ecb99

Adjust install notes to clarify that Wine applies only to the Windows build. (Thanks to Perry Metzger for test-driving.)
author David A. Holland
date Sun, 26 Apr 2009 17:58:26 -0400
parents 13d2b8934445
children
line wrap: on
line source

{
/*
Copyright 1992, Jerome T. Holland
See the file COPYING for license and usage terms.
*/

#include "ssd.h"
#include "kb.h"
#include "num.h"

}

cell name request  = 255
input line request = 254
block request      = 253

[
  ~allow macros
  ~backtrack
  ~case sensitive
  ~declare pcb
  ~diagnose errors
   error trace
  ~lines and columns
   pointer input
  ~test range
   rule coverage
   parser file name = "#.cpp"
   default token type = number
   disregard space
]

letter = 'A-Z'
bound variable = 'A-Z'
digit = '0-9'
nonzero digit = '1-9'
eof = 0
space = ' '
decimal point = '.'
pi = 'ã'             //character code 227


(void) grammar
 -> cell name request, cell name:cp, eof  =goto_cell = cp;
 -> input line request, input line
 -> conditional expression:x,
    ['\n', conditional expression]..., eof  =xvalue = x;
 -> block request, cell name:f, to, cell name:l,
    eof =first_cell=f, last_cell = l;

(void) input line
 -> cell name: loc, '='   =stuff_cell(loc);
 -> '@',cell name:f, to, cell name:l,'/',
    format:fmt, eof       =stuff_format(fmt,f,l);

to
 -> '.', '.'?

(format_code) format
 ->'a',':', alignment:a, ',',
   'c',':', conversion:c, ',',
   'd',':', integer:n  ={
   format_code f;
   f.alignment = a;
   f.conversion =c;
   f.decimals = n;
   f.flag = 0;
   return f;
}

(int) alignment
 -> 'L' =0;
 -> 'C' =1;
 -> 'R' =2;

(int) conversion
 -> 'C' =0;
 -> 'F' =1;
 -> 'G' =2;

(pair<int>) cell name
 -> column id:col, integer:row    =id_cell(row-1,col);

(int) column id
 -> letter:a, letter:b            =rel_column_id(a-'A'+1, b-'A');
 -> letter:a                      =rel_column_id(0, a-'A');

(int) integer
 -> nonzero digit:d               =d-'0';
 -> integer:n, digit:d            =10*n + d-'0';

conditional expression
 -> x expression
 -> expression:x, ':', disjunction:c, ';', conditional expression:y ={
  number z;
  switch (c.tv){
  case 0:
    z = y;
    break;
  case 1:
    z = x;
    break;
  case 2:
    z.error = 1;
  }
  return z;
}

disjunction
 -> conjunction
 -> disjunction:x, '|', conjunction:y  =x||y;

conjunction
 -> logical value
 -> conjunction:x, '&', logical value:y   =x&&y;

logical value
 -> comparison
 -> '(', disjunction:x, ')'           =x;
 -> '!', '(', disjunction:x, ')'      =!x;

comparison
 -> partial comparison:x, '<', expression:y =x<y;
 -> partial comparison:x, '>', expression:y =x>y;
 -> partial comparison:x, "<=", expression:y =x<=y;
 -> partial comparison:x, ">=", expression:y =x>=y;
 -> partial comparison:x, "==", expression:y =x==y;
 -> partial comparison:x, "!=", expression:y =x!=y;

partial comparison
 -> x expression
 -> comparison

x expression
 -> expression
 -> summation
 -> expression:x, '+', summation:y     =x+y;
 -> expression:x, '-', summation:y     =x-y;

expression
 -> term
 -> expression:x, '+', term:y     =x+y;
 -> expression:x, '-', term:y     =x-y;

term
 -> xxfactor
 -> term:x, '*', xxfactor:y               =x*y;

xxfactor
 -> xfactor
 -> function:f, xfactor:y                  =apply(f,y);
 -> factor:x, function:f, xfactor:y        =x*apply(f,y);

xfactor
 -> yfactor
 -> base:x, '^', xfactor:n                 =pow(x,n);
 -> '-', xfactor:x                         =-x;

yfactor
 -> factor
 -> yfactor:x, '/', factor:y               =x/y;

factor
 -> simple factor
 -> simple factor:x, r value:y        =x*y;
 -> r value

simple factor
 -> l value
 -> c value
 -> simple factor:x, c value:y        =x*y;

l value
 -> number

c value
 -> cell name:cp                    =cell_value(cp);
 -> parens
 -> pi                              =num(M_PI);
 -> sigma, cell name:first, '.', '.'?, cell name:last  =sum_cells(first,last);

r value
 -> bound variable:k                =bound_variable[k-'A'];

summation
 -> sigma:xb, x expression string:xf, ':', bound variable:k, '=',
    x expression:f, ',', x expression:s, "...", x expression:l =
     summation(xb,xf,k-'A', f, s, l);

(char *) sigma
 -> 'ä'    =(char *)PCB.pointer;      //character code 228

(char *) x expression string
 -> x expression  =(char *)PCB.pointer;

base
 -> l value
 -> c value
 -> r value

parens
 -> '(', conditional expression:x, ')'     =x;

(function_name) function
 -> "abs"  =fabs;
 -> "acos" = acos;
 -> "asin" = asin;
 -> "atan" = atan;
 -> "cosh" = cosh;
 -> "cos"  =cos;
 -> "exp"  =exp;
 -> "log10" = log10;
 -> "log"   = log;
 -> "pow10" = pow10d;
 -> "round" = round;
 -> "sinh" = sinh;
 -> "sin"  =sin;
 -> "sqr"  =sqr;
 -> "sqrt" = sqrt;
 -> "tanh" = tanh;
 -> "tan"  = tan;
 -> "trunc" = trunc;

number
 -> integer part:x, decimal point?                     =num(x);
 -> integer part:x, decimal point, fraction part:y     =num(x+y);
 -> decimal point, fraction part:x                     =num(x);

(double) integer part
 -> digit:d    =d-'0';
 -> integer part:n, digit:d  =10*n+d-'0';

(double) fraction part
 -> digit:d                   =(d-'0')/10.;
 -> digit:d, fraction part:f  =(d-'0'+f)/10.;

{
fp_pcb_type *fp_pcb;
#define PCB (*fp_pcb)


#define CELL_NAME_REQUEST 255
#define INPUT_LINE_REQUEST 254
#define BLOCK_REQUEST 253

#define SYNTAX_ERROR
#define PARSER_STACK_OVERFLOW

static int cell_refs;
static int error_flag;

static number bound_variable[26];
static number xvalue;

number num(double x) {
  number n;
  n.error = 0;
  n.truth = 1;
  n.v = x;
  return n;
}

void init_bv(void) {
  int i;
  for (i = 0; i < 26; i++) bound_variable[i].error = 1;
}

double round(double x) {
  long n = x+.5;
  return n;
}

double trunc(double x) {
  long n = x;
  return n;
}

double sqr(double x) {
  return x*x;
}

double pow10d(double x) {
  long n = x;
  return pow10d(n);
}

number cell_value(pair<int> loc) {
  number x;
  cell_pointer cp;
  int save_ef = error_flag;

  cell_refs++;
  cp = ss[loc.row][loc.col];
  if (cp == NULL) {
    x.truth = 1;
    x.v = 0;
    return x;
  }
  if (cp->type == text) {
    x.error = 1;
    x.truth = 0;
    return x;
  }
  if (cp->type == formula) {
    if ((inserted_columns || inserted_rows));
    else if (recalc_flag) {
      if (cp->recalc == recalc_count) eval(cp);
      if (cp->recalc & 1) circular_flag = 1;
    }
  }
  x.error = cp->error;
  x.truth = 1;
  x.v = cp->value;
  return x;
}

void eval(cell_pointer cp) {
  fp_pcb_type pcb, *save_pcb = fp_pcb;

  fp_pcb = &pcb;
  cell_refs = 0;
  PCB.pointer = (unsigned char *) &cp->text;
  cp->recalc += recalc_flag;
  error_flag = 0;
  fp();
  cp->recalc += recalc_flag;
  if (PCB.exit_flag != 1) {cp->type = text; cp->error = 1; return;}
  else if (cell_refs == 0) cp->type = value;
  else cp->type = formula;
  {
    cp->error = xvalue.error;
    cp->value = xvalue.v;
  }
  fp_pcb = save_pcb;
}

number evalx(char *xs) {
  fp_pcb_type pcb, *save_pcb = fp_pcb;
  number x;

  fp_pcb = &pcb;
  PCB.pointer = (unsigned char *) xs;
  error_flag = 0;
  fp();
  fp_pcb = save_pcb;
  return xvalue;
}

pair<int> id_cell(int row, int col) {
  pair<int> goto_cell = {0,0};
  if (row >= MAXROWS || col >= MAXCOLS) {
    PCB.exit_flag = 5;
    return goto_cell;
  }
  if (inserted_rows && row >= new_row) row += inserted_rows;
  goto_cell.row = row;
  goto_cell.col = col;
  if (inserted_columns == 0 && inserted_rows == 0) return goto_cell;
  sprintf((char *)icnptr,"%d",row+1);
  icnptr += strlen((char *)icnptr);
  icoptr = PCB.pointer;
  return goto_cell;
}

int matherr(struct exception *e) {
  error_flag++;
  e->retval = 0;
  return 1;
}

number apply(double(*f)(double), number n) {
  number r;
  if (n.error) return n;
  error_flag = 0;
  r.v = f(n.v);
  r.error = error_flag != 0;
  return r;
}

number pow(number x, number n) {
  number r;
  r.error = x.error || n.error;
  if (r.error) return r;
  r.v = pow(x.v, n.v);
  return r;
}

void parse_block(void) {
  int flag;
  fp_pcb_type pcb;

  fp_pcb = &pcb;
  PCB.pointer = (unsigned char *) text_buffer;
  text_buffer[0] = BLOCK_REQUEST;
  fp();
  flag = PCB.exit_flag != 1
       || first_cell.row > last_cell.row
       || first_cell.col > last_cell.col
       || last_cell.row > MAXROWS
       || last_cell.col > MAXCOLS;
  if (flag) {
    kb_pcb.reduction_token = kb_bad_block_token;
    display_message(&bad_block_message);
    set_cursor(text_cursor);
  }
  else _setcursortype(_NOCURSOR);
}

void parse_cell_name(void) {
  int flag;
  fp_pcb_type pcb;

  fp_pcb = &pcb;
  PCB.pointer = (unsigned char *) text_buffer;
  text_buffer[0] = CELL_NAME_REQUEST;
  fp();
  flag = PCB.exit_flag != 1
       || goto_cell.row > MAXROWS
       || goto_cell.col > MAXCOLS;
  if (flag) {
    kb_pcb.reduction_token = kb_bad_cell_name_token;
    display_message(&bad_cell_message);
    set_cursor(text_cursor);
  }
  else _setcursortype(_NOCURSOR);
}

int rel_column_id(int a, int b) {
  int cn = 26*a + b;
  int nidc = a?2:1;
  int n;
  unsigned char case_bit = 0;
  char *cp;

  if (inserted_columns == 0 && inserted_rows == 0) return cn;
  if (cn >= new_column) cn += inserted_columns;
  n = (PCB.pointer - icoptr) - nidc;
  memmove((char *)icnptr, (char *)icoptr, n);
  icnptr += n;
  cp = (char *)PCB.pointer;
  while (nidc--) case_bit |= *--cp;
  case_bit &= 0x20;
  cp = column_label(cn,case_bit);
  strcpy((char *)icnptr,cp);
  icnptr += strlen(cp);
  return cn;
}

void relabel_formula(cell_pointer cp) {
  fp_pcb_type pcb, *save_pcb = fp_pcb;

  fp_pcb = &pcb;
  icoptr = PCB.pointer = (unsigned char *) &cp->text;
  icnptr = (unsigned char *) relabel_buf;
  fp();
  assert(PCB.exit_flag == 1);
  strcpy((char *)icnptr, (char *)icoptr);
  cp = (cell_descriptor *) realloc(cp, sizeof(cell_descriptor) + strlen(relabel_buf));
  assert(cp);
  strcpy(cp->text, relabel_buf);
  fp_pcb = save_pcb;
}

void scan_input_line(void) {
  fp_pcb_type pcb, *save_pcb = fp_pcb;

  fp_pcb = &pcb;
  PCB.pointer = (unsigned char *) text_buffer;
  text_buffer[0] = INPUT_LINE_REQUEST;
  fp();
  fp_pcb = save_pcb;
}

void set_column_width(void) {
  int n;
  char *tb = text_buffer + 1;
  int flag;

  highlight_off();
  for (n = 0; *tb;) n = 10*n + *tb++ - '0';
  flag = n < 3 || n > 75;
  if (flag) {
    kb_pcb.reduction_token = kb_column_width_request_token;
    display_message(&bad_cw_message);
    beep();
    set_cursor(text_cursor);
    return;
  }
  _setcursortype(_NOCURSOR);
  if (ac.scc.col + n > 81) move_data_left();
  cols[ac.ssc.col].width = n;
  display_column_guide();
  update_screen();
  highlight_on();
}


void stuff_cell(pair<int> loc) {
  char *tb = (char *) fp_pcb->pointer;
  cell_pointer cp = (cell_descriptor *) realloc(
    ss[loc.row][loc.col],
    sizeof(cell_descriptor) + strlen(tb));

  assert(cp);
  if (loc.row > max_row) max_row = loc.row;
  if (loc.col > max_col) max_col = loc.col;
  strcpy(cp->text, tb);
  ss[loc.row][loc.col] = cp;
  cp->recalc = recalc_count;
  eval(cp);
}

void stuff_format(format_code f,pair<int> first,pair<int> last){
  int i,j;
  for (i=first.row;i<=last.row;i++) for (j=first.col;j<=last.col;j++) {
    fmt[i][j] = f;
  }
  if (last.row > fmt_max_row) fmt_max_row = last.row;
  if (last.col > fmt_max_col) fmt_max_col = last.col;
}

number sum_cells(pair<int> first,pair<int> last){
  pair<int> cp;
  number sum;
  sum.error = sum.truth = 1;
  sum.v = 0;
  for (cp.row = first.row; cp.row <= last.row; cp.row++)
  for (cp.col = first.col; cp.col <= last.col; cp.col++) {
    number cv = cell_value(cp);
    if (cv.error) return sum;
    sum.v += cv.v;
  }
  sum.error = 0;
  return sum;
}

number summation(char *xb, char *xf, int bv, number f, number s, number l) {
  number sum;
  int k;
  char *xs;
  number delta;
  int n;

  sum.error = f.error + s.error + l.error;
  sum.v = 0;
  if (sum.error) return sum;
  k = (int) (xf - xb);
  xs = (char *) malloc(k+1);
  memmove(xs,xb,k);
  xs[k] = 0;
  delta = s-f;
  if (delta.v == 0) {
    sum.error = 1;
    return sum;
  }
  n = ((l-f+delta)/delta).v + .5;
  while (n--) {
    bound_variable[bv] = f;
    sum = sum + evalx(xs);
    if (sum.error) break;
    f = f+delta;
  }
  bound_variable[bv].error = 1;
  free(xs);
  return sum;
}


}