view tests/agcl/contrib/yabasic.syn @ 24:a4899cdfc2d6 default tip

Obfuscate the regexps to strip off the IBM compiler's copyright banners. I don't want bots scanning github to think they're real copyright notices because that could cause real problems.
author David A. Holland
date Mon, 13 Jun 2022 00:40:23 -0400
parents 13d2b8934445
children
line wrap: on
line source

{

/*
     YABASIC --- a tiny integrated Basic Compiler/Interpreter

     BISON - part

     this Program is subject to the GNU General Public License;
     see the file yabasic.c for details.
*/


//#undef WINDOWS
#include "yabasic.h"     /* definitions of yabasic */
#include <malloc.h>

#if HAVE_ALLOCA_H
#include <alloca.h>
#endif

void __yy_bcopy(char *,char *,int); /* prototype missing */

int yylineno=1;
int yylex(void);

char *popString(int);
void pushChar(int);

}

[
  ~case sensitive
  disregard white space
  lexeme {digit string, name, STRING, STRSYM, number}
  distinguish lexemes
  parser name = parseBasic
  line numbers
  escape backslashes
]

white space = ' ' + '\t'

//(double *) step_part


SEP
 -> ["REM", ~(eof + white space + '\n')?...], '\n'      ={
     yylineno++;
     if (interactive) PCB.exit_flag = AG_SUCCESS_CODE;
     return;
 }

(double) number
 -> 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';

(int) name           //value of name token is length of name string
 -> letter: c                                       =pushChar(c), 1;
 -> name:k, letter+digit: c                       =pushChar(c), k+1;


(char *) SYMBOL
  -> name:k                                   =strdup(popString(k));

(char *) STRSYM
  -> name:k, '$'                              =pushChar('$'), strdup(popString(k+1));

(char *) DIGITS
  -> digit string:k                                  =strdup(popString(k));

(int) digit string
 -> digit:d                                         =pushChar(d), 1;
 -> digit string:k, digit:d                         =pushChar(d), k+1;

(char *) STRING
 -> '"', string text:k, '"'                         =strdup(popString(k));
 -> '"', string text:k, '\n'                        =strdup(popString(k));

(int) string text
 ->                                                 =0;
 -> string text:k, ~(eof + '"' + '\n'):c            =pushChar(c), k+1;
 -> string text:k, "\\\""                           =pushChar('"'), k+1;

/*
[
  left {"OR"}
  left {"AND"}
  left {"NOT"}
  left {'-', '+'}
  left {'*', '/'}
  left {'^'}
  nonassoc {UMINUS}
]
*/

letter = 'a-z' + 'A-Z'
digit  = '0-9'
eof = 0 + -1


program $
 -> statement list, eof             =end_of_file = TRUE;

statement list
 ->
/*
 -> statement_list, !{
if (errorlevel<=ERROR) {YYABORT;}},
   SEP, !{
yylineno+=$3;},
   statement
*/
 -> statement list, SEP, statement
 -> statement list, SEP, label, statement

label
 -> "LABEL", SYMBOL:s                =create_label(s);
 -> DIGITS:s                         =create_label(s);


statement  /* empty */
 ->
 -> string_assignment
 -> assignment
 -> for_loop
 -> if_clause
 -> "GOTO", symbol_or_lineno:s ={create_goto(s);}
 -> "GOSUB", symbol_or_lineno:s ={create_gosub(s);}
 -> "ON", "INTERRUPT", "BREAK" ={create_exception(TRUE);}
 -> "ON", "INTERRUPT", "CONTINUE" ={create_exception(FALSE);}
 -> "ON", expression, "GOTO", !{create_skipper();}, goto_list ={create_nop();}
 -> "ON", expression, "GOSUB", !{create_skipper();}, gosub_list ={create_nop();}
// -> LABEL, symbol_or_lineno ={create_label($2);}
 -> "OPEN", hashed_number:n, ',', string expression, ',', string expression ={create_myopen(n,'+');}
 -> "OPEN", hashed_number:n, ',', string expression ={create_myopen(n,'-');}
 -> "CLOSE", hashed_number:n ={create_myclose(n);}
 -> "PRINT", printintro, printlist, !{
create_revert(FALSE);},
   semicolon
 -> "INPUT", inputintro, inputlist =lastinput->args=0;
 -> "READ", readlist
 -> "DATA", datalist
 -> "RESTORE" =create_restore("");
 -> "RESTORE", symbol_or_lineno:s =create_restore(s);
 -> "RETURN" ={create_return();}
 -> "DIM", dimlist
 -> "OPEN", "WINDOW", expression, ',', expression =create_openwin(FALSE);
 -> "OPEN", "WINDOW", expression, ',', expression, ',', string expression ={create_openwin(TRUE);}
 -> "DOT", mapping                    =create_dot();
 -> "LINE", mapping, "TO", mapping =create_line('l');
 -> "CIRCLE", mapping, ',', expression =create_circle();
 -> "TEXT", string expression, ',', mapping =create_text(TRUE);
 -> "TEXT", mapping, ',', string expression =create_text(FALSE);
 -> "MAP", expression, ',', expression, ',', expression, ',', expression, "TO", expression, ',', expression, ',', expression, ',', expression =create_makemap();
 -> "ARROW", mapping, "TO", mapping =create_line('a');
 -> "XTICK", mapping, ',', string expression =create_tick(1);
 -> "YTICK", mapping, ',', string expression =create_tick(3);
 -> "XTICK", mapping =create_tick(0);
 -> "YTICK", mapping =create_tick(2);
 -> "CLOSE", "WINDOW" =create_closewin();
 -> "CLEAR", "WINDOW" =create_clearwin();
 -> "CLEAR", "SCREEN" =create_clearscreen();
 -> "OPEN", "PRINTER" =create_openprinter(0);
 -> "OPEN", "PRINTER", string expression =create_openprinter(1);
 -> "CLOSE", "PRINTER" =create_closeprinter();
 -> "WAIT", expression =create_mywait();
 -> "BELL" =create_bell();
 -> "INKEY" ={create_function(MYINKEY); create_popstrsym(NULL);}
 -> "SYSTEM2", '(', string expression, ')' ={create_function(MYSYSTEM2);
	create_popdblsym(NULL);}
 -> "POKE", string expression, ',', string expression ={create_poke('s');}
 -> "POKE", string expression, ',', expression ={create_poke('d');}
 -> "END" ={create_myend();}

string_assignment
 -> STRSYM:s, '=', string expression ={create_popstrsym(s);}
 -> "MID", '(', STRSYM:s, !{
create_pushstrptr(s);},
   ',', expression, ',', expression, ')', '=', string expression ={create_changestring(MYMID);}
 -> "LEFT", '(', STRSYM:s, !{
create_pushstrptr(s);},
   ',', expression, ')', '=', string expression ={create_changestring(MYLEFT);}
 -> "RIGHT", '(', STRSYM:s, !{
create_pushstrptr(s);},
   ',', expression, ')', '=', string expression ={create_changestring(MYRIGHT);}
 -> STRSYM:s, '(', !{
pushcounter();},
   indexlist, ')', '=', string expression ={create_doarray(s,ASSIGNSTRINGARRAY);}
 -> "MID", '(', STRSYM:s, '(', !{
pushcounter();},
   indexlist, ')', !{
create_doarray(s,GETSTRINGPOINTER);},
   ',', expression, ',', expression, ')', '=', string expression ={create_changestring(MYMID);}
 -> "LEFT", '(', STRSYM:s, '(', !{
pushcounter();},
   indexlist, ')', !{
create_doarray(s,GETSTRINGPOINTER);},
   ',', expression, ')', '=', string expression ={create_changestring(MYLEFT);}
 -> "RIGHT", '(', STRSYM:s, '(', !{
pushcounter();},
   indexlist, ')', !{
create_doarray(s,GETSTRINGPOINTER);},
   ',', expression, ')', '=', string expression ={create_changestring(MYRIGHT);}

string expression
 -> primary string expression
 -> string expression, '+', primary string expression ={create_concat();}

primary string expression
 -> STRSYM:s ={create_pushstrsym(s);}
 -> string_function
 -> STRING:s ={if (s==NULL) {error(ERROR,"String not terminated");create_pushstr("");} else {create_pushstr(s);}}
 -> STRSYM:s, '(', !{
pushcounter();},
   indexlist, ')' ={create_doarray(s,CALLSTRINGARRAY);}
 -> '(', string expression, ')'

string_function
 -> "LEFT", '(', string expression, ',', expression, ')' ={create_function(MYLEFT);}
 -> "RIGHT", '(', string expression, ',', expression, ')' ={create_function(MYRIGHT);}
 -> "MID", '(', string expression, ',', expression, ',', expression, ')' ={create_function(MYMID);}
 -> "STR", '(', expression, ')' ={create_function(MYSTR);}
 -> "STR", '(', expression, ',', string expression, ')' ={create_function(MYSTR2);}
 -> "INKEY" ={create_function(MYINKEY);}
 -> "CHR", '(', expression, ')' ={create_function(MYCHR);}
 -> "UPPER", '(', string expression, ')' ={create_function(MYUPPER);}
 -> "LOWER", '(', string expression, ')' ={create_function(MYLOWER);}
 -> "LTRIM", '(', string expression, ')' ={create_function(MYLTRIM);}
 -> "RTRIM", '(', string expression, ')' ={create_function(MYRTRIM);}
 -> "TRIM", '(', string expression, ')' ={create_function(MYTRIM);}
 -> "SYSTEM", '(', string expression, ')' ={create_function(MYSYSTEM);}
 -> "DATE" ={create_function(MYDATE);}
 -> "TIME" ={create_function(MYTIME);}
 -> "PEEK2", '(', string expression, ')' ={create_function(MYPEEK2);}

assignment
 -> SYMBOL:s, '=', expression ={create_popdblsym(s);}
 -> SYMBOL:s, '(', !{
pushcounter();},
   indexlist, ')', '=', expression ={create_doarray(s,ASSIGNARRAY);}

primary expression
 -> number:n                           =create_pushdbl(n);
 -> function
 -> SYMBOL:s                           =create_pushdblsym(s);
 -> SYMBOL:s, '(', !pushcounter();,
      indexlist, ')'                   ={create_doarray(s,CALLARRAY);}
 -> '(', expression, ')'
 -> '-', primary expression /* 1ef4:fa2arec <֠ */ ={create_negate();}

exponential expression
 -> primary expression
 -> exponential expression, '^', primary expression ={create_dblbin('^');}

multiplicative expression
 -> exponential expression
 -> multiplicative expression, '*', exponential expression ={create_dblbin('*');}
 -> multiplicative expression, '/', exponential expression ={create_dblbin('/');}

expression
 -> multiplicative expression
 -> expression, '+', multiplicative expression ={create_dblbin('+');}
 -> expression, '-', multiplicative expression ={create_dblbin('-');}

/*
 -> expression, '+', expression ={create_dblbin('+');}
 -> expression, '-', expression ={create_dblbin('-');}
 -> expression, '*', expression ={create_dblbin('*');}
 -> expression, '/', expression ={create_dblbin('/');}
 -> expression, '^', expression ={create_dblbin('^');}
 -> '-', expression /* 1ef4:fa2arec <֠ * / ={create_negate();}
*/

mapping
 -> expression, ',', expression
 -> "MAP", '(', expression, ',', expression, ')' ={create_map();}

function
 -> "SIN", '(', expression, ')' ={create_function(MYSIN);}
 -> "ASIN", '(', expression, ')' ={create_function(MYASIN);}
 -> "COS", '(', expression, ')' ={create_function(MYCOS);}
 -> "ACOS", '(', expression, ')' ={create_function(MYACOS);}
 -> "TAN", '(', expression, ')' ={create_function(MYTAN);}
 -> "ATAN", '(', expression, ')' ={create_function(MYATAN);}
 -> "ATAN", '(', expression, ',', expression, ')' ={create_function(MYATAN2);}
 -> "EXP", '(', expression, ')' ={create_function(MYEXP);}
 -> "LOG", '(', expression, ')' ={create_function(MYLOG);}
 -> "SQRT", '(', expression, ')' ={create_function(MYSQRT);}
 -> "INT", '(', expression, ')' ={create_function(MYINT);}
 -> "FRAC", '(', expression, ')' ={create_function(MYFRAC);}
 -> "MOD", '(', expression, ',', expression, ')' ={create_function(MYMOD);}
 -> "RAN", '(', expression, ')' ={create_function(MYRAN);}
 -> "RAN", '(', ')' ={create_function(MYRAN2);}
 -> "MIN", '(', expression, ',', expression, ')' ={create_function(MYMIN);}
 -> "MAX", '(', expression, ',', expression, ')' ={create_function(MYMAX);}
 -> "XMAP", '(', expression, ')' ={create_function(MYXMAP);}
 -> "YMAP", '(', expression, ')' ={create_function(MYYMAP);}
 -> "LEN", '(', string expression, ')' ={create_function(MYLEN);}
 -> "VAL", '(', string expression, ')' ={create_function(MYVAL);}
 -> "ASC", '(', string expression, ')' ={create_function(MYASC);}
 -> "INSTR", '(', string expression, ',', string expression, ')' ={create_function(MYINSTR);}
 -> "SYSTEM2", '(', string expression, ')' ={create_function(MYSYSTEM2);}
 -> "PEEK", '(', string expression, ')' ={create_function(MYPEEK);}

(double) const
 -> number:n =n;
 -> '+', number:n =n;
 -> '-', number:n =-n;

/*
number
 -> FNUM ={$$=$1;}
 -> DIGITS ={$$=atoi($1);}
*/

(int) intnum
 -> DIGITS:d                            =atoi(d);

(char *) symbol_or_lineno
 -> DIGITS:s =s;
 -> SYMBOL:s =s;

dimlist
 -> SYMBOL:s, '(', !{
pushcounter();},
   indexlist, ')' ={create_dim(s,'d');}
 -> dimlist, ',', SYMBOL:s, '(', !{
pushcounter();},
   indexlist, ')' ={create_dim(s,'d');}
 -> STRSYM:s, '(', !{
pushcounter();},
   indexlist, ')' ={create_dim(s,'s');}
 -> dimlist, ',', STRSYM:s, '(', !{
pushcounter();},
   indexlist, ')' ={create_dim(s,'s');}

indexlist
 -> expression ={inccounter();}
 -> indexlist, ',', expression ={inccounter();}

for_loop
 -> "FOR", SYMBOL:s, '=', expression, !{
pushname(s);create_popdblsym(s);pushgoto();
             create_pushdblsym(s);},
   "TO", expression, step_part:p, !{

       create_dblrelop((p>0)?'{':'}');
             create_decide();
             pushlabel();},
/*
   SEP, !{
yylineno+=$10;},
*/ SEP,
   statement list, !{
             create_pushdbl(p);
       create_pushdblsym(s);
             create_dblbin('+');
       create_popdblsym(s);
             swap();popgoto();poplabel();},
   next_or_eofile, next_symbol                    ={/* cookie*/}

next_or_eofile
 -> "NEXT"
 -> eof ={end_of_file=TRUE;
      error(ERROR,"'next'-statement is missing"); PCB.exit_flag = AG_SYNTAX_ERROR_CODE;}

(double) step_part
 ->  /* can be omitted */ =1.0;
 -> "STEP", const:v =v;

next_symbol
 -> /* can be omitted */ ={pop();}
 -> SYMBOL:s ={if (strcmp(pop()->pointer,s))
             {error(ERROR,"'for' and 'next' do not match"); PCB.exit_flag = AG_SYNTAX_ERROR_CODE;}
           }

if_clause
 -> "IF", condition, !{
create_decide();pushlabel();},
   "THEN", statement list, !{
pushlabel();swap();poplabel();},
   else_part, !{
poplabel();},
   endif_or_eof

endif_or_eof
 -> "ENDIF"
 -> eof ={end_of_file=TRUE;
            error(ERROR,"'endif'-statement is missing"); PCB.exit_flag = AG_SYNTAX_ERROR_CODE;}
/*
condition
 -> '(', condition, ')'
 -> condition, "OR", condition ={create_boole('|');}
 -> "NOT", condition ={create_boole('!');}
*/

condition
 -> and condition
 -> condition, "OR", and condition ={create_boole('|');}


and condition
 -> primary condition
 -> and condition, "AND", primary condition ={create_boole('&');}

primary condition
 -> comparison
 -> '(', condition, ')'
 -> "NOT", primary condition

comparison
 -> string expression, '=', string expression ={create_strrelop('=');}
 -> string expression, "<>", string expression ={create_strrelop('!');}
 -> string expression, '<', string expression ={create_strrelop('<');}
 -> string expression, "<=", string expression ={create_strrelop('{');}
 -> string expression, '>', string expression ={create_strrelop('>');}
 -> string expression, ">=", string expression ={create_strrelop('}');}
 -> expression, '=', expression ={create_dblrelop('=');}
 -> expression, "<>", expression ={create_dblrelop('!');}
 -> expression, '<', expression ={create_dblrelop('<');}
 -> expression, "<=", expression ={create_dblrelop('{');}
 -> expression, '>', expression ={create_dblrelop('>');}
 -> expression, ">=", expression ={create_dblrelop('}');}
 //-> MYEOF, '(', hashed_number, ')' ={create_testeof($3);}

else_part /* can be omitted */
 ->
 -> "ELSE", statement list

inputlist
 -> input
 -> input, ',', inputlist

input
 -> SYMBOL:s ={create_myread('d');create_popdblsym(s);}
 -> SYMBOL:s, '(', !{
pushcounter();},
   indexlist, ')' ={create_myread('d');create_doarray(s,ASSIGNARRAY);}
 -> STRSYM:s ={create_myread('s');create_popstrsym(s);}
 -> STRSYM:s, '(', !{
pushcounter();},
   indexlist, ')' ={create_myread('s');create_doarray(s,ASSIGNSTRINGARRAY);}

readlist
 -> readitem
 -> readlist, ',', readitem

readitem
 -> SYMBOL:s ={create_readdata('d');create_popdblsym(s);}
 -> SYMBOL:s, '(', !{
pushcounter();},
   indexlist, ')' ={create_readdata('d');create_doarray(s,ASSIGNARRAY);}
 -> STRSYM:s ={create_readdata('s');create_popstrsym(s);}
 -> STRSYM:s, '(', !{
pushcounter();},
   indexlist, ')' ={create_readdata('s');create_doarray(s,ASSIGNSTRINGARRAY);}

datalist
 -> STRING:s ={create_strdata(s);}
 -> const:v ={create_dbldata(v);}
 -> datalist, ',', STRING:s ={create_strdata(s);}
 -> datalist, ',', const:v ={create_dbldata(v);}

printlist  /* possible empty */
 ->
 -> expression ={create_print('d');}
 -> printlist, ',', expression ={create_print('d');}
 -> string expression ={create_print('s');}
 -> printlist, ',', string expression ={create_print('s');}

inputintro
 ->  ={create_myswitch(0);create_readline(NULL);}
 -> stream
 -> position ={create_myswitch(0);create_readline(NULL);}
 -> !{
create_myswitch(0);},
   prompt
 -> position, !{
create_myswitch(0);},
   prompt

printintro
 ->  /* can be empty */ ={create_myswitch(0);}
 -> stream
 -> "REVERSE" ={create_revert(TRUE);create_myswitch(0);}
 -> position ={create_myswitch(0);}
 -> "REVERSE", position ={create_revert(TRUE);create_myswitch(0);}

prompt
 -> STRING:s ={create_readline(s);}

position
 -> "AT", '(', expression, ',', expression, ')' ={create_mymove();}

stream
 -> '#', intnum:n ={create_myswitch(n);}

(int) hashed_number
 -> '#', intnum:n =n;
 -> intnum:n /* need not contain hash */ =n;

semicolon /* can be left out */
 ->  ={create_print('n');}
 -> ';'

goto_list
 -> symbol_or_lineno:s ={create_goto(s);create_findnop();}
 -> goto_list, ',', symbol_or_lineno:s ={create_goto(s);create_findnop();}

gosub_list
 -> symbol_or_lineno:s ={create_gosub(s);create_findnop();}
 -> gosub_list, ',', symbol_or_lineno:s ={create_gosub(s);create_findnop();}

{
#define CHAR_STACK_LENGTH 500

static char  charStack[CHAR_STACK_LENGTH+1];
static char *charStackTop = charStack;

/* Define an error record */
typedef struct {
  char *message;                 /* identifies error */
  int line;                      /* location of error */
  int column;
} ErrorRecord;

ErrorRecord errorRecord;           /* define an error record */

void diagnoseError(char *msg) {
  if (parseBasic_pcb.exit_flag == AG_RUNNING_CODE)
    parseBasic_pcb.exit_flag = AG_SEMANTIC_ERROR_CODE;      /* stop parse */
  errorRecord.message = msg;
  errorRecord.line    = parseBasic_pcb.line;
  errorRecord.column  = parseBasic_pcb.column;
}

void pushChar(int c) {              /* append char to name string */
  if (charStackTop < charStack+CHAR_STACK_LENGTH) {
    *charStackTop++ = (char) c;
    return;
  }
  /* buffer overflow, kill parse and issue diagnostic */
  diagnoseError("Character Stack Overflow");
}

static char *popString(int nChars) {                /* get string */
  *charStackTop = 0;
  return charStackTop -= nChars;
}

FILE *parserInputFile;
void switch_to_my_file(FILE *inputfile) /* switches lex input to given file */
{
  parserInputFile = inputfile;
  return;
}

#define GET_INPUT ((PCB).input_code = fgetc(parserInputFile))

int yyparse() {
  parseBasic();
  return !(PCB.exit_flag == AG_SUCCESS_CODE);
}


}