view tests/agcl/parsifal/ss-kb.syn @ 15:f5acaf0c8a29

Don't cast through "volatile int". Causes a gcc warning nowadays. XXX: should put something else back here to frighten the optimizer
author David A. Holland
date Tue, 31 May 2022 01:00:55 -0400
parents 13d2b8934445
children
line wrap: on
line source

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

/* Keyboard syntax for Sample Spreadsheet */

backspace          = '\b'
delete             = 339
letter             = 'a-z' + 'A-Z'
digit              = '0-9'
eof                = 0
any key            =~eof
yes                ='y' + 'Y'
no                 =~yes

text character     = 32..127

up                 = 328
page up            = 329
left               = 331
right              = 333
down               = 336
page down          = 337
control page up    = 388
control page down  = 374
control left       = 371
control right      = 372
home               = 327
control home       = 375
end                = 335
control end        = 373
escape             = 27
return             = '\r'

alt x              = 301

F1                 = 315
F2                 = 316

file error message   = !display_message(&file_error_msg);
goto query           = !accept_text(&goto_msg,"");
load name query      = !accept_text(&load_from_msg, file_name);
no such file message = !accept_text(&nonexistent_msg, file_name);
overwrite query      = !display_message(&file_exists_msg);
save changes query   = !display_message(&changes_msg);
save name query      = !accept_text(&save_to_msg, file_name);
print file query     = !accept_text(&print_to_msg, file_name);
block query          = !accept_text(&block_msg,"");
decimals query       = !accept_text(&decimals_msg, "");
bad decimals message = !accept_text(&bad_decimals_msg,NULL);

[
//  sticky edit text
 ~allow macros
  default token type = void
 ~lines and columns
 ~diagnose errors
  reduction choices
  parser file name = "#.cpp"
]


grammar
 -> {top level command =update_status();}..., eof

top level command
 -> recalc request                    =recalc();
 -> utility menu, 'f' + 'F'           =toggle_formula_display();
 -> main menu, 'a'+'A'                =autocalc_flag = !autocalc_flag;
// -> edit request, edit text, return?  =set_cell_text();
 -> edit request, edit text, return   =set_cell_text();
 -> edit request, edit text, escape
 -> delete request                    =delete_cell();
 -> page up                           =page_up();
 -> page down                         =page_down();
 -> control left                      =scroll_left();
 -> control right                     =scroll_right();
 -> home                              =home();
 -> end                               =end();
 -> up                                =cursor_up();
 -> down                              =cursor_down();
 -> left                              =cursor_left();
 -> right                             =cursor_right();
 -> load file
 -> save file
 -> clear spreadsheet
 -> format
 -> exit                              =quit();
 -> error
 -> goto
 -> column menu, 'i' + 'I'            =insert_column();
 -> column menu, 'd' + 'D'            =delete_column();
 -> column width
 -> row menu, 'i' + 'I'               =insert_row();
 -> row menu, 'd' + 'D'               =delete_row();
 -> any menu, escape
 -> print menu, 'o' + 'O', print file name    =print();

any menu
 -> main menu
 -> spreadsheet menu
 -> utility menu
 -> column menu
 -> row menu

format
 -> format menu, 'c' + 'C', block                 =set_conversion(currency);
 -> format menu, 'g' + 'G', block                 =set_conversion(general);
 -> format menu, 'f' + 'F', digits spec:n, block  =set_decimals(n);
 -> label menu, how:h, block                      =set_alignment(h);

(int) how
 -> 'l' + 'L'  =LEFT;
 -> 'c' + 'C'  =CENTER;
 -> 'r' + 'R'  =RIGHT;

(int) digits spec, bad digits spec
 -> decimals query, edit number, return               =check_digits();
 -> bad digits spec, bad decimals message, edit number, return =check_digits();

recalc request
 -> F1
 -> utility menu, 'r' + 'R'

delete request
 -> delete
 -> main menu, 'd' + 'D'

goto
 -> main menu, 'g' + 'G', goto query, cell name      =go();

column width request
 -> column menu, 'w' + 'W'          =accept_text(&col_width_msg,"");

column width, column width request
 -> column width request, edit number, return    =set_column_width();

column width
 -> column width request, edit number, escape

cell name, bad cell name
 -> edit text, return                  =parse_cell_name();
 -> edit text, escape
 -> bad cell name, edit text, return   =parse_cell_name();
 -> bad cell name, edit text, escape

block, bad block
 -> block query, edit text, return     =parse_block();
 -> block query, edit text, escape
 -> bad block, edit text, return       =parse_block();
 -> bad block, edit text, escape

exit
 -> exit request, save changes

exit request
 -> main menu, 'q' + 'Q'
 -> alt x

load file
 -> spreadsheet menu, 'l' + 'L', save changes, load spreadsheet

save file
 -> spreadsheet menu, 's' + 'S', save spreadsheet

save changes
 -> not changed
 -> changed, save changes query, no
 -> changed, save changes query, yes, save spreadsheet

changed, not changed
 -> !STATUS(n_changes, changed);

save spreadsheet
 -> save name query, write file
 -> save name query, old file, overwrite query, no, save spreadsheet

load spreadsheet
 -> load name query, old file      =load_file();
 -> load name query, new file, no such file message, load spreadsheet

print file name
 -> print file query, new file
 -> print file query, old file, overwrite query, yes
 -> print file query, old file, overwrite query, no, print file name

new file, old file
 -> edit text, return                     =check_file_name();

write file, file error
 -> new file                       =write_file();
 -> old file, overwrite query, yes =write_file();

write file
 -> file error, file error message, any key

clear spreadsheet
 -> clear spreadsheet request, yes      =clear();
 -> clear spreadsheet request, no

clear spreadsheet request
 -> spreadsheet menu, 'c' + 'C'    =display_message(&clear_spreadsheet);

main menu
 -> '/'                            =display_menu(&main_menu);

spreadsheet menu
 -> main menu, 's' + 'S'           =display_menu(&spreadsheet_menu);

column menu
 -> main menu, 'c' + 'C'           =display_menu(&column_menu);

row menu
 -> main menu, 'r' + 'R'           =display_menu(&row_menu);

utility menu
 -> main menu, 'u' + 'U'           =display_menu(&utility_menu);

format menu
 -> main menu, 'f' + 'F'           =display_menu(&format_menu);

label menu
 -> format menu, 'l' + 'L'         =display_menu(&label_menu);

print menu
 -> spreadsheet menu, 'p' + 'P'    =pm_msg();
 -> print menu, 'w' + 'W' + 'n' + 'N'  =print_wide = !print_wide, pm_msg();
 -> print menu, 'l' + 'L'          =(print_border = !print_border),pm_msg();
 -> print menu, 'b' + 'B',
    block =print_block=TRUE,print_from=first_cell,print_to=last_cell,pm_msg();

edit request
 -> F2                             =init_cell_edit();
 -> main menu, 'e' + 'E'           =init_cell_edit();
 -> text character - '/':c         =init_text_input(c);
 -> ^S                             =init_text_input('ä');    //228
 -> ^P                             =init_text_input('ã');    //227

(void) edit text
 ->
 -> edit text, text character:c =insert_char(c);
 -> edit text, ^S       =insert_char(228);
 -> edit text, ^P       =insert_char(227);
 -> edit text, edit key

(void) edit number
 ->
 -> edit number, digit:d =insert_char(d);
 -> edit number, edit key

(void) edit key
 -> backspace           =backspace_char();
 -> delete              =delete_char();
 -> left                =text_cursor_left();
 -> right               =text_cursor_right();
 -> home                =text_cursor_home();
 -> end                 =text_cursor_end();
 -> error               =beep();

{
#include "ssd.h"

char text_buffer[100];
int text_index;
pair<int> text_cursor = {INPUT_LINE, 1};

#define GET_INPUT {int c;\
  PCB.input_code = ((c=getch()) != 0 ? c : getch()+256);}

#define SYNTAX_ERROR

#define STATUS(x,y) PCB.reduction_token = (x)?kb_##y##_token:kb_not_##y##_token

void beep(void) {
  sound(440);
  delay(75);
  nosound();
}

void accept_text(message *m, char *t) {
  display_message(m);
  init_text_edit(t);
}

void backspace_char(void) {
  if (text_cursor.col == 1) return;
  text_cursor_left();
  delete_char();
}

int check_digits(void){
  char *tb = text_buffer + 1;
  int n;
  for (n = 0; *tb;) n = 10*n + *tb++ - '0';
  if (n > 7) CHANGE_REDUCTION(bad_digits_spec);
  return n;
}

void delete_cell(void) {
  cell_pointer cp = ss[ac.ssc.row][ac.ssc.col];
  if (cp) free(cp);
  ss[ac.ssc.row][ac.ssc.col] = NULL;
  update_cell(ac.scc, ac.ssc);
  set_active_cell();
}

void delete_char(void) {
  strcpy(&text_buffer[text_cursor.col], &text_buffer[text_cursor.col+1]);
  display_field(
    text_cursor,
    SCREEN_WIDTH - text_cursor.col,
    LEFT,
    TEXT_COLOR,
    "%s",
    &text_buffer[text_cursor.col]
  );
  set_cursor(text_cursor);
}

void delete_column(void) {
  int i,j;
  new_column = ac.ssc.col;
  for (i = 0; i < MAXROWS; i++) if (ss[i][new_column]) free(ss[i][new_column]);
  for (i = new_column; i < max_col; i++)
    for (j = 0; j <= max_row; j++)
      ss[j][i] = ss[j][i+1];
  for (j = 0; j <= max_row; j++) ss[j][max_col] = NULL;
  max_col--;
  inserted_columns = -1;
  relabel(0,new_column);
  new_column = inserted_columns = 0;
}

void delete_row(void) {
  int i,j;
  new_row = ac.ssc.row;
  for (i = 0; i < MAXCOLS; i++) if (ss[new_row][i]) free(ss[new_row][i]);
  for (i = new_row; i < max_row; i++)
    for (j = 0; j <= max_col; j++)
      ss[i][j] = ss[i+1][j];
  for (j = 0; j <= max_col; j++) ss[max_row][j] = NULL;
  max_row--;
  inserted_rows = -1;
  relabel(new_row,0);
  new_row = inserted_rows = 0;
}

void init_cell_edit(void) {
  cell_pointer cp = ss[ac.ssc.row][ac.ssc.col];
  if (cp) strcpy(text_buffer+1, cp->text);
  else text_buffer[1] = 0;
  text_cursor.col = strlen(text_buffer+1) + 1;
  textattr(TEXT_COLOR);
  _setcursortype(_NORMALCURSOR);
  input_msg.msg = text_buffer+1;
  display_message(&input_msg);
  set_cursor(text_cursor);
}

void init_text_edit(char *c) {
  if (c) strcpy(text_buffer+1, c);
  text_cursor.col = strlen(text_buffer+1) + 1;
  textattr(TEXT_COLOR);
  _setcursortype(_NORMALCURSOR);
  input_msg.msg = text_buffer+1;
  display_message(&input_msg);
  set_cursor(text_cursor);
}

void init_text_input(int c) {
  textattr(TEXT_COLOR);
  _setcursortype(_NORMALCURSOR);
  text_buffer[text_cursor.col = 1] = c;
  set_cursor(text_cursor);
  putch(c);
  text_buffer[++text_cursor.col] = 0;
}

void insert_char(int c){
  int n = strlen(&text_buffer[text_cursor.col]);
  memmove(&text_buffer[text_cursor.col+1], &text_buffer[text_cursor.col], n+1);
  text_buffer[81] = 0;
  text_buffer[text_cursor.col++] = c;
  putch(c);
  display_field(text_cursor, n, LEFT, TEXT_COLOR, &text_buffer[text_cursor.col]);
  set_cursor(text_cursor);
}

void insert_column(void) {
  int i,j;
  if (max_col + 1 >= MAXCOLS) {
    for (i = 0; i < MAXROWS; i++) if (ss[i][max_col]) free(ss[i][max_col]);
  }
  max_col++;
  new_column = ac.ssc.col;
  for (i = max_col; i > new_column; i--)
    for (j = 0; j <= max_row; j++)
      ss[j][i] = ss[j][i-1];
  for (j = 0; j < MAXROWS; j++) ss[j][new_column] = NULL;
  inserted_columns = 1;
  relabel(0,new_column);
  new_column = inserted_columns = 0;
}

void insert_row(void) {
  int i,j;
  if (max_row + 1 >= MAXROWS) {
    for (i = 0; i < MAXCOLS; i++) if (ss[max_row][i]) free(ss[max_row][i]);
  }
  max_row++;
  new_row = ac.ssc.row;
  for (i = max_row; i > new_row; i--)
    for (j = 0; j <= max_col; j++)
      ss[i][j] = ss[i-1][j];
  for (j = 0; j < MAXCOLS; j++) ss[new_row][j] = NULL;
  inserted_rows = 1;
  relabel(new_row,0);
  new_row = inserted_rows = 0;
}

void recalc(void) {
  int i,j;
  recalc_flag = 1;
  circular_flag = 0;
  for (i = 0; i <= max_row; i++) for (j = 0; j <= max_col; j++) {
    cell_pointer cp = ss[i][j];

    if (cp == NULL || cp->type != formula) continue;
    if (cp->recalc == recalc_count) eval(cp);
  }
  recalc_count += 2;
  recalc_flag = 0;
  update_screen();
  set_active_cell();
}

void relabel(int row, int col) {
  int i,j;

  n_changes++;
  for (i = row; i <= max_row; i++) for (j = col; j <= max_col; j++) {
    cell_pointer cp = ss[i][j];

    if (cp == NULL || cp->type != formula) continue;
    relabel_formula(cp);
  }
  update_screen();
  set_active_cell();
}

void set_cell_text(void) {
  char *tb = text_buffer + 1;
  cell_pointer cp = realloc(
    ss[ac.ssc.row][ac.ssc.col],
    sizeof(cell_descriptor) + strlen(tb)
  );
  n_changes++;
  assert(cp);
  if (ac.ssc.row > max_row) max_row = ac.ssc.row;
  if (ac.ssc.col > max_col) max_col = ac.ssc.col;
  strcpy(cp->text, tb);
  cp->error = 0;
  ss[ac.ssc.row][ac.ssc.col] = cp;
  cp->recalc = recalc_count;
  _setcursortype(_NOCURSOR);
  eval(cp);
  if (cp->type != text && autocalc_flag) recalc();
  else {
    update_cell(ac.scc, ac.ssc);
    set_active_cell();
  }
}

void text_cursor_end(void) {
  while (text_buffer[text_cursor.col]) {
    text_cursor.col++;
  }
  set_cursor(text_cursor);
}

void text_cursor_home(void) {
  if (text_cursor.col == 1) return;
  text_cursor.col = 1;
  set_cursor(text_cursor);
}

void text_cursor_left(void) {
  if (text_cursor.col == 1) return;
  text_cursor.col--;
  set_cursor(text_cursor);
}

void text_cursor_right(void) {
  if (text_buffer[text_cursor.col] == 0) return;
  if (text_cursor.col >= SCREEN_WIDTH) return;
  text_cursor.col++;
  set_cursor(text_cursor);
}

void toggle_formula_display(void) {
  formula_flag = !formula_flag;
  display_message(&form_msg);
  update_screen();
  set_active_cell();
}

}