view tests/agcl/oldagsrc/xvmc.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

{
/*
 XVMC.SYN

 Extensible Scripting Language
 Copyright (c) 1998 Parsifal Software, All Rights Reserved.

 The expression syntax is borrowed from C but with the
 addition of the FORTRAN exponentiation operator (**).

 The supported operations are:
   Assignment operators:        =, +=, -=, *=, /=, %=, , &=, |=, ^=>>=, <<=
   Conditional expressions:     ? :
   Logical operators:           !, &&, ||
   Bitwise logical operators:   &, |, ^, ~
   Comparison operators:        ==, !=, <, <=, >, >=
   Shift operators:             <<, >>
   Binary arithmetic operators: +, -, *, /, %
   Unary arithmetic operators:  +, -
   Exponentiation:              **
   Autoincrement operators:     ++, --;
   Cast operators               (<type name>)
   Parentheses
   Function calls
   Object method calls

 Built in data types are int, double and String.

 Statements may include variable declarations, expression statements,
 blocks, if/else statements, while , do/while, or for statements,
 following the rules of C.

 The statement syntax has been written to avoid the conventional
 if/else ambiguity.

 Input strings may contain any number of statements. White space may be
 used freely, including both C and C++ style comments.

 xvmc.syn is compiled with the AnaGram parser generator
 yielding xvm.h and xvm.cpp.

 For information about AnaGram, visit http://www.parsifalsoft.com.
*/

#include <math.h>
#include "xvm.h"                  // defines external interface
#include "integer.h"
#include "double.h"
#include "xstring.h"

static VirtualMachine *vm;

typedef VirtualMachine::CodeSeg Code;             // For the sake of readability

}
// -- CONFIGURATION SECTION ----------------------------
[
  default token type = Code
  disregard white space
  lexeme {real, name string, string literal, character constant}
  distinguish lexemes
  distinguish keywords {'a-z' + 'A-Z' + '0-9' + '_'}
  pointer input
  parser name = vmCompile
  parser file name = "#.cpp"
  line numbers
  ~allow macros
  escape backslashes                        // for Visual C++
]

input string $                       // specify grammar token
 -> eof                                     =Code();
 -> statements:x, eof                       =x;
 -> statements:x, error, ~(eof + ';' + '}' + space)?..., eof   =x;

statement
 -> executable statement
 -> declaration, ';'
 -> error, ~(eof + ';' + '}' + space)?..., ';'       =errorLog.add("Continuing scan"), Code();

declaration
 -> type name:t, name string:n                           =vm->declareVariable(t,n), Code();
 -> type name:t, name string:n, '=', expression:x   ={
    int name = vm->declareVariable(t,n);
    return Code(VirtualMachine::PUSHV) << name << x << VirtualMachine::ASSIGN << VirtualMachine::POP;
 }
 -> type name:t, name string:n, '[', expression:size, ']'    =vm->declareArray(t,n, size);
 -> type name:t, name string:n, '(', expression list:args, ')' =vm->declareObject(t,n,args);

expression list
 ->                                                          =Code();
 -> expressions:x                                            =x;

expressions
 -> expression:x                                             =x.initList();
 -> expressions:list, ',', expression:x                      =list.append(x);


executable statement
 -> unconditional statement
 -> conditional statement

statements
 -> statement:x                                =x;
 -> statements:x, statement:s                  =x << s;


/*
 An unconditional statement is any statement that does not involve
 an if statement
*/

unconditional statement
 -> expression:x, ';'                          =x << VirtualMachine::POP;
 -> ';'                                        =Code();
 -> '{', '}'                                   =Code();
 -> '{', statements:s, '}'                     =s;
 -> '{', statements:s, error, ~(eof + ';' + '}' + space)?..., '}'   =errorLog.add("Continuing scan"), s;
 -> "do", executable statement:s, while clause:x, ';'  =vm->codeDoWhile(s,x);
 -> while clause:x, unconditional statement:s          =vm->codeWhile(x,s);
 -> "for", '(', for exprs:init, ';', condition:cond, ';', for exprs:inc,
    ')', unconditional statement:s                     =vm->codeFor(init, cond, inc, s);

for exprs
 ->                                             =Code();
 -> for expr list

for expr list
 -> expression:x                                =x << VirtualMachine::POP;
 -> for expr list:list, ',', expression:x       =list << x << VirtualMachine::POP;

while clause
 -> "while", '(', condition:x, ')'            =x;


/*
 Any statement with an if in it is a conditional statement
*/

conditional statement
 -> while clause:x, conditional statement:s         =vm->codeWhile(x,s);
 -> "for", '(', for exprs:init, ';', condition:cond, ';', for exprs:inc,
    ')', conditional statement:s                     =vm->codeFor(init, cond, inc, s);
 -> if clause:x, executable statement:s             =x << VirtualMachine::BRF << s.size() << s;
 -> if clause:x, unconditional statement:s1,
      "else", statement:s2                     ={
      s1 << VirtualMachine::BR << s2.size();
      x << VirtualMachine::BRF << s1.size() << s1 << s2;
      return x;
    }

if clause
 -> "if", '(', condition:x, ')'               =x;

condition
 -> expression:x                              =x.testOK();

expression
 -> conditional expression
 -> lvalue:k, '=',  expression:x                 =k << x << VirtualMachine::ASSIGN;
 -> lvalue:k, "+=", expression:x                 =k << x << VirtualMachine::ADD_EQ;
 -> lvalue:k, "-=", expression:x                 =k << x << VirtualMachine::SUB_EQ;
 -> lvalue:k, "*=", expression:x                 =k << x << VirtualMachine::MULT_EQ;
 -> lvalue:k, "/=", expression:x                 =k << x << VirtualMachine::DIV_EQ;
 -> lvalue:k, "%=", expression:x                 =k << x << VirtualMachine::MOD_EQ;
 -> lvalue:k, "|=", expression:x                 =k << x << VirtualMachine::OR_EQ;
 -> lvalue:k, "&=", expression:x                 =k << x << VirtualMachine::AND_EQ;
 -> lvalue:k, "^=", expression:x                 =k << x << VirtualMachine::XOR_EQ;
 -> lvalue:k, "<<=", expression:x                =k << x << VirtualMachine::LS_EQ;
 -> lvalue:k, ">>=", expression:x                =k << x << VirtualMachine::RS_EQ;

lvalue
 -> variable name:k                              =Code(VirtualMachine::PUSHV).setType(vm->symbolTable[k].type) << k;
 -> lvalue:k, '[', expression:x, ']'             =k.setType(k.type->element) << x << VirtualMachine::SUBSCRIPT;

conditional expression
 -> logical or expression
 -> logical or condition:c, '?',
      expression:x, ':', conditional expression:y    ={
      //if (!c.type->isTruthDefined()) errorLog.add("True/False not defined");
      x << VirtualMachine::BR << y.size();
      c << VirtualMachine::BRF << x.size() << x << y;
      return c;
    }

logical or condition
 -> logical or expression:x     =x.testOK();

logical or expression
 -> logical and expression
 -> logical or condition:x, "||",logical and expression:y        ={
      //if (!x.type->isTruthDefined()) errorLog.add("True/False not defined");
      return x << VirtualMachine::OR << y.size() << y;
    }

logical and expression
 -> bitwise or expression
 -> logical and condition:x, "&&", bitwise or expression:y          ={
      //if (!x.type->isTruthDefined()) errorLog.add("True/False not defined");
      return x << VirtualMachine::AND << y.size() << y;
    }

logical and condition
 -> logical and expression:x     =x.testOK();



bitwise or expression
 -> bitwise xor expression
 -> bitwise or expression:x, '|',
      bitwise xor expression:y         =x.binop(VirtualMachine::BITOR,y);

bitwise xor expression
 -> bitwise and expression
 -> bitwise xor expression:x, '^',
      bitwise and expression:y         =x.binop(VirtualMachine::XOR,y);

bitwise and expression
 -> equality expression
 -> bitwise and expression:x, '&',
      equality expression:y             =x.binop(VirtualMachine::BITAND,y);

equality expression
 -> relational expression
 -> equality expression:x, "==", relational expression:y    =x.binop(VirtualMachine::EQ,y);
 -> equality expression:x, "!=", relational expression:y    =x.binop(VirtualMachine::NE,y);

relational expression
 -> shift expression
 -> relational expression:x, '<',  shift expression:y    =x.binop(VirtualMachine::LT,y);
 -> relational expression:x, "<=", shift expression:y    =x.binop(VirtualMachine::LE,y);
 -> relational expression:x, '>',  shift expression:y    =x.binop(VirtualMachine::GT,y);
 -> relational expression:x, ">=", shift expression:y    =x.binop(VirtualMachine::GE,y);

shift expression
 -> additive expression
 -> shift expression:x, "<<", additive expression:y  =x.binop(VirtualMachine::LS,y);
 -> shift expression:x, ">>", additive expression:y  =x.binop(VirtualMachine::RS,y);

additive expression
 -> multiplicative expression
 -> additive expression:x, '+',
      multiplicative expression:y                          =x.binop(VirtualMachine::ADD,y);
 -> additive expression:x, '-',
      multiplicative expression:y                          =x.binop(VirtualMachine::SUB,y);

multiplicative expression
 -> cast expression
 -> multiplicative expression:x, '*', cast expression:y           =x.binop(VirtualMachine::MULT,y);
 -> multiplicative expression:x, '/', cast expression:y           =x.binop(VirtualMachine::DIV,y);
 -> multiplicative expression:x, '%', cast expression:y           =x.binop(VirtualMachine::MOD,y);

cast expression
 -> unary expression
 -> '(', type name:t, ')', cast expression:x                      =x.cast((VirtualMachine::Type::Id) t) << VirtualMachine::CAST << t;

unary expression
 -> power expression
 -> "++", unary expression:x                             =x << VirtualMachine::INCR;
 -> "--", unary expression:x                             =x << VirtualMachine::INCR;
 -> '-', unary expression:x                              =x << VirtualMachine::NEG;
 -> '+', unary expression:x                              =x;
 -> '!', unary expression:x                              =vm->list(stdout), x << VirtualMachine::NOT;
 -> '~', unary expression:x                              =x << VirtualMachine::COMPL;



power expression
 -> primary
 -> primary:x, "**", unary expression:y                  =x.binop(VirtualMachine::POW,y);

primary
 -> real:x                                      =vm->doubleList.push(x), Code(VirtualMachine::PUSHD).setType(&DoubleType::doubleType) << (int)(vm->doubleList.size() - 1);
 -> integer constant:x                          =Code(VirtualMachine::PUSHI).setType(&IntegerType::intType) << x;
 -> string literal:k                            =Code(VirtualMachine::PUSHS).setType(&StringType::stringType) << k;
 -> lvalue:k                                    =k;
 -> lvalue:k, "++"                              =k << VirtualMachine::PUSH << VirtualMachine::INCR << VirtualMachine::POP;
 -> lvalue:k, "--"                              =k << VirtualMachine::PUSH << VirtualMachine::DECR << VirtualMachine::POP;
 -> name string:n, '(', expression list:args, ')'  =vm->invokeFunction(n, args);
 -> lvalue:k, '.', name string:n, '(', expression list: args, ')' =vm->invokeMethod(k, n, args);
 -> '(', expression:x, ')'                      =x;

// -- LEXICAL UNITS ------------------------------------------------
digit   = '0-9'
eof     = 0
letter  = 'a-z' + 'A-Z' + '_'
space =  ' ' + '\t' + '\f' + '\v' + '\r' + '\n'


(void) white space
 -> space
 -> "/*", ~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:i, '.', fraction part:f                           = i+f;
 -> integer:i, '.'                                               =i;
 -> '.', fraction part:f                                        = f;

(int) integer constant
 -> integer
 -> character constant

(int) integer
 -> digit:d                                                 = d-'0';
 -> integer: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) type name, variable name
 -> name string:k           ={
    char *name = popString(k);
    VirtualMachine::Type::Id id = VirtualMachine::Type::idType(name);
    if (id != VirtualMachine::Type::UNDEFINED) return (int) id;
    CHANGE_REDUCTION(variable_name);
    return vm->locateVariable(name);
 }

(int) name string
 -> letter: c                                       =pushChar(c), 1;
 -> name string:k, letter+digit: c                  =pushChar(c), k+1;

not double quote    = ~eof - ('"' + '\\' + '\n')
not single quote    = ~eof - ('\'' + '\\' + '\n')

(int) character constant
 -> '\'', char constant element:c, '\''     =c;

(int) char constant element
 -> not single quote
 -> escape sequence

(int) string literal
  -> string chars:k, '"'                    =vm->stringList.push(CharString(popString(k))), vm->stringList.size() - 1;

(int) string chars
  -> '"'                                    =0;
  -> string chars:k, string char:c          =pushChar(c), k+1;

(int) string char
 -> not double quote
 -> escape sequence

(int) escape sequence
 -> "\\a"   ='\a';
 -> "\\b"   ='\b';
 -> "\\f"   ='\f';
 -> "\\n"   ='\n';
 -> "\\r"   ='\r';
 -> "\\t"   ='\t';
 -> "\\v"   ='\v';
 -> "\\\\"  ='\\';
 -> "\\?"   = '\?';
 -> "\\'"   ='\'';
 -> "\\\""  ='"';
 -> octal escape
 -> hex escape

(int) octal escape
 -> one octal | two octal | three octal

(int) one octal
 -> '\\', '0-7':d                           =d-'0';

(int) two octal
 -> one octal:n, '0-7':d                    =8*n + d-'0';

(int) three octal
 -> two octal:n, '0-7':d                    =8*n + d-'0';

(int) hex escape
 -> "\\x", hex digit:d                      =d;
 -> hex escape:n, hex digit:d               =16*n + d;

(int) hex digit
 -> '0-9'
 -> 'a-f' + 'A-F':d                         =(d&7) + 9;

[
   sticky {one octal, two octal, hex escape}
]



{ // begin embedded C

#include <string.h>


ErrorRecord::ErrorRecord(char *msg) : message(msg), line(PCB.line), column(PCB.column)
{/* Initializers do it all */}

ErrorLog errorLog;

#define SYNTAX_ERROR errorLog.add(PCB.error_message)

int VirtualMachine::compile(char *text) {
  vm = this;
  resetCharStack();
  vmCompile_pcb.pointer = (unsigned char *) text;
  vmCompile();
  {
    Code program = vmCompile_value() << EXIT;
    int n = program.size();
    codeStore = new int[n];
    while (n--) codeStore[n] = program[n];
  }

  return vmCompile_pcb.exit_flag != AG_SUCCESS_CODE;
}

Code VirtualMachine::codeWhile(Code x, Code s) {
  Code branch(VirtualMachine::BR);
  branch << 0;
  //if (!x.type->isTruthDefined()) errorLog.add("True/False not defined");
  x << VirtualMachine::BRF << (s.size() + branch.size());
  int blockLength = s.size() + x.size() + branch.size();
  x << s << VirtualMachine::BR << -blockLength;
  return x;
}

Code VirtualMachine::codeDoWhile(Code s, Code x) {
  Code branch(VirtualMachine::BR);
  branch << 0;
  int blockLength = s.size() + x.size() + branch.size();
  //if (!x.type->isTruthDefined()) errorLog.add("True/False not defined");
  s << x << VirtualMachine::BRT << -blockLength;
  return s;
}

Code VirtualMachine::codeFor(Code init, Code cond, Code inc, Code s) {
  s << inc;               // append increment code to end of body of for loop
  //if (!cond.type->isTruthDefined()) errorLog.add("True/False not defined");
  init << codeWhile(cond, s);
  return init;
}

} // end of embedded C
/********************* End of VM.SYN ************************/