view tests/agcl/parsifal/ss-fp.syn @ 21:1c9dac05d040

Add lint-style FALLTHROUGH annotations to fallthrough cases. (in the parse engine and thus the output code) Document this, because the old output causes warnings with gcc10.
author David A. Holland
date Mon, 13 Jun 2022 00:04:38 -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;
}


}