Adds comparison operators and bool.
This commit is contained in:
parent
9c831134ae
commit
5a6be7e742
9 changed files with 214 additions and 50 deletions
|
@ -1,5 +1,5 @@
|
|||
# -fsanitize=address
|
||||
CFLAGS=
|
||||
CFLAGS=-g
|
||||
CCFLAGS=$(CFLAGS) -std=c++11 -c
|
||||
LFLAGS=$(CFLAGS) -o tsvm
|
||||
|
||||
|
|
|
@ -1,38 +1,8 @@
|
|||
|
||||
# Trainscript Test File
|
||||
VAR v1' : REAL;
|
||||
VAR v2' : REAL;
|
||||
VAR temp : BOOL;
|
||||
|
||||
# Execute some stuff
|
||||
PUB main(x : INT) → c : INT
|
||||
physics();
|
||||
factorial(2);
|
||||
42 → c;
|
||||
|
||||
# Physics exercise with elastic collision
|
||||
PRI physics() | m1:REAL, v1:REAL, m2:REAL, v2:REAL
|
||||
# Wagen 1
|
||||
4.0 → m1;
|
||||
1.2 → v1;
|
||||
|
||||
# Wagen 2
|
||||
5.0 → m2;
|
||||
0.6 → v2;
|
||||
|
||||
(((m1 - m2) * v1) + (2. * m2 * v2)) / (m1 + m2) → v1';
|
||||
(((m2 - m1) * v2) + (2. * m1 * v1)) / (m1 + m2) → v2';
|
||||
|
||||
# Recursive test
|
||||
PUB fibonacci(n : INT) → f : INT
|
||||
#IF n = 0
|
||||
0 → f;
|
||||
#ELSEIF n = 1
|
||||
1 → f;
|
||||
#ELSE
|
||||
fibonacci(n - 1) + fibonacci(n - 2) → f;
|
||||
|
||||
PUB factorial(number : INT) → result : INT
|
||||
#IF number <= 1
|
||||
1 → result;
|
||||
#ELSE
|
||||
number * factorial(number - 1) → result;
|
||||
BEGIN
|
||||
(x =/= c) → temp;
|
||||
x → c;
|
||||
END
|
||||
|
|
38
trainscript/file02.ts
Normal file
38
trainscript/file02.ts
Normal file
|
@ -0,0 +1,38 @@
|
|||
|
||||
# Trainscript Test File
|
||||
VAR v1' : REAL;
|
||||
VAR v2' : REAL;
|
||||
|
||||
# Execute some stuff
|
||||
PUB main(x : INT) → c : INT
|
||||
physics();
|
||||
factorial(2);
|
||||
42 → c;
|
||||
|
||||
# Physics exercise with elastic collision
|
||||
PRI physics() | m1:REAL, v1:REAL, m2:REAL, v2:REAL
|
||||
# Wagen 1
|
||||
4.0 → m1;
|
||||
1.2 → v1;
|
||||
|
||||
# Wagen 2
|
||||
5.0 → m2;
|
||||
0.6 → v2;
|
||||
|
||||
(((m1 - m2) * v1) + (2. * m2 * v2)) / (m1 + m2) → v1';
|
||||
(((m2 - m1) * v2) + (2. * m1 * v1)) / (m1 + m2) → v2';
|
||||
|
||||
# Recursive test
|
||||
PUB fibonacci(n : INT) → f : INT
|
||||
#IF n = 0
|
||||
0 → f;
|
||||
#ELSEIF n = 1
|
||||
1 → f;
|
||||
#ELSE
|
||||
fibonacci(n - 1) + fibonacci(n - 2) → f;
|
||||
|
||||
PUB factorial(number : INT) → result : INT
|
||||
#IF number <= 1
|
||||
1 → result;
|
||||
#ELSE
|
||||
number * factorial(number - 1) → result;
|
|
@ -67,11 +67,7 @@ int main(int argc, char** argv)
|
|||
printf("Variable: %s : %s = ",
|
||||
var.first.c_str(),
|
||||
typeName(var.second->type.id));
|
||||
switch(var.second->type.id) {
|
||||
case TypeID::Int: printf("%d", var.second->integer); break;
|
||||
case TypeID::Real: printf("%f", var.second->real); break;
|
||||
default: printf("???"); break;
|
||||
}
|
||||
var.second->printval();
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
|
|
@ -11,8 +11,7 @@
|
|||
%option yylineno
|
||||
%%
|
||||
\#[^\n]* ; // Eat all the comments!
|
||||
[ ]+ ; // Eat all the whitespace!
|
||||
\t { return TAB; }
|
||||
[ \t]+ ; // Eat all the whitespace!
|
||||
\; { return SEMICOLON; }
|
||||
\: { return COLON; }
|
||||
\, { return COMMA; }
|
||||
|
@ -26,16 +25,39 @@
|
|||
\% { return MODULO; }
|
||||
\-\>|→ { return RARROW; }
|
||||
\<\-|← { return LARROW; }
|
||||
|
||||
\< { return OP_LT; }
|
||||
\<\= { return OP_LE; }
|
||||
\> { return OP_GT; }
|
||||
\>\= { return OP_GE; }
|
||||
\= { return OP_EQ; }
|
||||
\≠|\=\/\= { return OP_NEQ; }
|
||||
|
||||
VAR { return KW_VAR; }
|
||||
PUB { return KW_PUB; }
|
||||
PRI { return KW_PRI; }
|
||||
PTR { return KW_PTR; }
|
||||
|
||||
VOID { return KW_VOID; }
|
||||
INT { return KW_INT; }
|
||||
REAL { return KW_REAL; }
|
||||
TEXT { return KW_TEXT; }
|
||||
BOOL { return KW_BOOL; }
|
||||
|
||||
BEGIN { return KW_BEGIN; }
|
||||
END { return KW_END; }
|
||||
IF { return KW_IF; }
|
||||
ELSE { return KW_ELSE; }
|
||||
REPEAT { return KW_REPEAT; }
|
||||
FROM { return KW_FROM; }
|
||||
TO { return KW_TO; }
|
||||
UNTIL { return KW_UNTIL; }
|
||||
WHILE { return KW_WHILE; }
|
||||
[0-9]+\.[0-9]* { yylval->fval = atof(yytext); return REAL; }
|
||||
[0-9]+ { yylval->ival = atoi(yytext); return INT; }
|
||||
[a-zA-Z0-9']+ { yylval->text = strdup(yytext); return IDENTIFIER; }
|
||||
. { yyerror(NULL, "illegal token"); }
|
||||
%%
|
||||
/*
|
||||
\t { return TAB; }
|
||||
*/
|
||||
|
|
|
@ -15,6 +15,13 @@ namespace trainscript {
|
|||
Variable multiply(Variable lhs, Variable rhs);
|
||||
Variable divide(Variable lhs, Variable rhs);
|
||||
Variable modulo(Variable lhs, Variable rhs);
|
||||
|
||||
Variable equals(Variable lhs, Variable rhs);
|
||||
Variable inequals(Variable lhs, Variable rhs);
|
||||
Variable less(Variable lhs, Variable rhs);
|
||||
Variable lessEqual(Variable lhs, Variable rhs);
|
||||
Variable greater(Variable lhs, Variable rhs);
|
||||
Variable greaterEqual(Variable lhs, Variable rhs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,6 +72,13 @@ void yyerror(void *scanner, const char *s);
|
|||
%token RARROW
|
||||
%token LARROW
|
||||
|
||||
%token OP_LT
|
||||
%token OP_LE
|
||||
%token OP_GT
|
||||
%token OP_GE
|
||||
%token OP_EQ
|
||||
%token OP_NEQ
|
||||
|
||||
%token <fval> REAL
|
||||
%token <ival> INT
|
||||
%token <text> IDENTIFIER
|
||||
|
@ -73,17 +87,32 @@ void yyerror(void *scanner, const char *s);
|
|||
%token KW_PRI
|
||||
%token KW_VAR
|
||||
%token KW_PTR
|
||||
|
||||
%token KW_VOID
|
||||
%token KW_INT
|
||||
%token KW_REAL
|
||||
%token KW_TEXT
|
||||
%token KW_BOOL
|
||||
|
||||
%token KW_BEGIN
|
||||
%token KW_END
|
||||
|
||||
%token KW_IF
|
||||
%token KW_ELSE
|
||||
%token KW_REPEAT
|
||||
%token KW_FROM
|
||||
%token KW_TO
|
||||
%token KW_UNTIL
|
||||
%token KW_WHILE
|
||||
|
||||
%type <type> typeName
|
||||
%type <varDecl> variableDeclaration
|
||||
%type <indentation> indentation
|
||||
|
||||
// %type <indentation> indentation
|
||||
|
||||
%type <method> method
|
||||
%type <methodHeader> methodDeclaration
|
||||
%type <body> block
|
||||
%type <body> body
|
||||
|
||||
%type <local> argument
|
||||
|
@ -101,6 +130,7 @@ void yyerror(void *scanner, const char *s);
|
|||
%start input
|
||||
|
||||
%left PLUS MINUS MULTIPLY DIVIDE MODULO RARROW
|
||||
%left OP_LT OP_LE OP_GT OP_GE OP_EQ OP_NEQ
|
||||
|
||||
%%
|
||||
input:
|
||||
|
@ -147,18 +177,22 @@ input:
|
|||
;
|
||||
|
||||
method:
|
||||
methodDeclaration body {
|
||||
methodDeclaration block {
|
||||
$$.header = $1;
|
||||
$$.body = $2;
|
||||
}
|
||||
;
|
||||
|
||||
block:
|
||||
KW_BEGIN body KW_END { $$ = $2; }
|
||||
;
|
||||
|
||||
body:
|
||||
%empty { $$ = nullptr; }
|
||||
| body indentation instruction SEMICOLON {
|
||||
| body instruction SEMICOLON {
|
||||
auto *body = new MethodBody();
|
||||
body->indentation = $2;
|
||||
body->instruction = $3;
|
||||
body->indentation = 0;
|
||||
body->instruction = $2;
|
||||
if($1 == nullptr) {
|
||||
$$ = body;
|
||||
} else {
|
||||
|
@ -266,6 +300,12 @@ expression:
|
|||
| expression MULTIPLY expression { $$ = new ArithmeticExpression<trainscript::ops::multiply>($1, $3); }
|
||||
| expression DIVIDE expression { $$ = new ArithmeticExpression<trainscript::ops::divide>($1, $3); }
|
||||
| expression MODULO expression { $$ = new ArithmeticExpression<trainscript::ops::modulo>($1, $3); }
|
||||
| expression OP_LT expression { $$ = new ArithmeticExpression<trainscript::ops::less>($1, $3); }
|
||||
| expression OP_LE expression { $$ = new ArithmeticExpression<trainscript::ops::lessEqual>($1, $3); }
|
||||
| expression OP_GT expression { $$ = new ArithmeticExpression<trainscript::ops::greater>($1, $3); }
|
||||
| expression OP_GE expression { $$ = new ArithmeticExpression<trainscript::ops::greaterEqual>($1, $3); }
|
||||
| expression OP_EQ expression { $$ = new ArithmeticExpression<trainscript::ops::equals>($1, $3); }
|
||||
| expression OP_NEQ expression { $$ = new ArithmeticExpression<trainscript::ops::inequals>($1, $3); }
|
||||
| expression RARROW IDENTIFIER { $$ = new VariableAssignmentExpression($3, $1); }
|
||||
;
|
||||
|
||||
|
@ -302,13 +342,15 @@ typeName:
|
|||
| KW_INT { $$.id = TypeID::Int; $$.pointer = 0; }
|
||||
| KW_REAL { $$.id = TypeID::Real; $$.pointer = 0; }
|
||||
| KW_TEXT { $$.id = TypeID::Text; $$.pointer = 0; }
|
||||
| KW_BOOL { $$.id = TypeID::Bool; $$.pointer = 0; }
|
||||
| KW_PTR LBRACKET typeName RBRACKET { $$ = $3; $$.pointer++; }
|
||||
;
|
||||
|
||||
/*
|
||||
indentation:
|
||||
TAB { $$ = 1; }
|
||||
| indentation TAB { $$ = $1 + 1; }
|
||||
;
|
||||
*/
|
||||
|
||||
%%
|
||||
|
||||
|
@ -317,5 +359,16 @@ indentation:
|
|||
#include "trainscript.l.h"
|
||||
|
||||
void yyerror(void *scanner, const char *s) {
|
||||
printf("Error: %s\n", s);
|
||||
if(scanner == nullptr) {
|
||||
printf("Error: %s\n", s);
|
||||
return;
|
||||
}
|
||||
int line = 0; // yyget_lineno(scanner);
|
||||
int col = 0; //yyget_column(scanner);
|
||||
char *text = yyget_text(scanner);
|
||||
printf(
|
||||
"[%d:%d] Error: %s at '%s'\n",
|
||||
line, col,
|
||||
s,
|
||||
text);
|
||||
}
|
||||
|
|
|
@ -17,12 +17,14 @@ namespace trainscript
|
|||
const Type Type::Int = { TypeID::Int, 0 };
|
||||
const Type Type::Real = { TypeID::Real, 0 };
|
||||
const Type Type::Text = { TypeID::Text, 0 };
|
||||
const Type Type::Boolean = { TypeID::Bool, 0 };
|
||||
|
||||
const Variable Variable::Invalid = { Type::Invalid };
|
||||
const Variable Variable::Void = { Type::Void };
|
||||
const Variable Variable::Int = { Type::Int };
|
||||
const Variable Variable::Real = { Type::Real };
|
||||
const Variable Variable::Text = { Type::Text };
|
||||
const Variable Variable::Boolean = { Type::Boolean };
|
||||
|
||||
Module *VM::load(const void *buffer, size_t length)
|
||||
{
|
||||
|
@ -160,5 +162,74 @@ namespace trainscript
|
|||
default: printf("modulo not supported for %s.\n", typeName(lhs.type.id)); return Variable::Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
Variable equals(Variable lhs, Variable rhs)
|
||||
{
|
||||
switch(lhs.type.id) {
|
||||
case TypeID::Int: return mkbool(lhs.integer == rhs.integer);
|
||||
case TypeID::Real: return mkbool(lhs.real == rhs.real);
|
||||
case TypeID::Bool: return mkbool(lhs.boolean == rhs.boolean);
|
||||
default:
|
||||
printf("equals not supported for %s.\n", typeName(lhs.type.id));
|
||||
return Variable::Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
Variable inequals(Variable lhs, Variable rhs)
|
||||
{
|
||||
switch(lhs.type.id) {
|
||||
case TypeID::Int: return mkbool(lhs.integer != rhs.integer);
|
||||
case TypeID::Real: return mkbool(lhs.real != rhs.real);
|
||||
case TypeID::Bool: return mkbool(lhs.boolean != rhs.boolean);
|
||||
default:
|
||||
printf("inequals not supported for %s.\n", typeName(lhs.type.id));
|
||||
return Variable::Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Variable less(Variable lhs, Variable rhs)
|
||||
{
|
||||
switch(lhs.type.id) {
|
||||
case TypeID::Int: return mkbool(lhs.integer < rhs.integer);
|
||||
case TypeID::Real: return mkbool(lhs.real < rhs.real);
|
||||
default:
|
||||
printf("equals not supported for %s.\n", typeName(lhs.type.id));
|
||||
return Variable::Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
Variable lessEqual(Variable lhs, Variable rhs)
|
||||
{
|
||||
switch(lhs.type.id) {
|
||||
case TypeID::Int: return mkbool(lhs.integer <= rhs.integer);
|
||||
case TypeID::Real: return mkbool(lhs.real <= rhs.real);
|
||||
default:
|
||||
printf("equals not supported for %s.\n", typeName(lhs.type.id));
|
||||
return Variable::Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
Variable greater(Variable lhs, Variable rhs)
|
||||
{
|
||||
switch(lhs.type.id) {
|
||||
case TypeID::Int: return mkbool(lhs.integer > rhs.integer);
|
||||
case TypeID::Real: return mkbool(lhs.real > rhs.real);
|
||||
default:
|
||||
printf("equals not supported for %s.\n", typeName(lhs.type.id));
|
||||
return Variable::Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
Variable greaterEqual(Variable lhs, Variable rhs)
|
||||
{
|
||||
switch(lhs.type.id) {
|
||||
case TypeID::Int: return mkbool(lhs.integer >= rhs.integer);
|
||||
case TypeID::Real: return mkbool(lhs.real >= rhs.real);
|
||||
default:
|
||||
printf("equals not supported for %s.\n", typeName(lhs.type.id));
|
||||
return Variable::Invalid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace trainscript
|
|||
using Int = int32_t;
|
||||
using Real = double;
|
||||
using Void = void;
|
||||
using Bool = bool;
|
||||
|
||||
extern bool verbose;
|
||||
|
||||
|
@ -55,6 +56,7 @@ namespace trainscript
|
|||
static const Type Int;
|
||||
static const Type Real;
|
||||
static const Type Text;
|
||||
static const Type Boolean;
|
||||
};
|
||||
|
||||
struct Variable
|
||||
|
@ -64,6 +66,7 @@ namespace trainscript
|
|||
Int integer;
|
||||
Real real;
|
||||
Text text;
|
||||
Bool boolean;
|
||||
};
|
||||
|
||||
void printval() const
|
||||
|
@ -71,6 +74,7 @@ namespace trainscript
|
|||
switch(this->type.id) {
|
||||
case TypeID::Int: printf("%d", this->integer); break;
|
||||
case TypeID::Real: printf("%f", this->real); break;
|
||||
case TypeID::Bool: printf("%s", this->boolean ? "TRUE" : "FALSE"); break;
|
||||
default: printf("???"); break;
|
||||
}
|
||||
}
|
||||
|
@ -80,6 +84,7 @@ namespace trainscript
|
|||
static const Variable Int;
|
||||
static const Variable Real;
|
||||
static const Variable Text;
|
||||
static const Variable Boolean;
|
||||
};
|
||||
|
||||
static inline Variable mkvar(Int value) {
|
||||
|
@ -94,6 +99,12 @@ namespace trainscript
|
|||
return v;
|
||||
}
|
||||
|
||||
static inline Variable mkbool(Bool value) {
|
||||
Variable v = Variable::Boolean;
|
||||
v.boolean = value;
|
||||
return v;
|
||||
}
|
||||
|
||||
class Module;
|
||||
|
||||
class LocalContext :
|
||||
|
@ -291,6 +302,7 @@ namespace trainscript
|
|||
switch(target->type.id) {
|
||||
case TypeID::Int: target->integer = result.integer; break;
|
||||
case TypeID::Real: target->real = result.real; break;
|
||||
case TypeID::Bool: target->boolean = result.boolean; break;
|
||||
default: if(verbose) printf("assignment not supported.\n"); break;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ namespace trainscript
|
|||
Int = 2,
|
||||
Real = 3,
|
||||
Text = 4,
|
||||
Bool = 5,
|
||||
};
|
||||
|
||||
static const char *typeName(TypeID id) {
|
||||
|
@ -18,6 +19,7 @@ namespace trainscript
|
|||
case TypeID::Int: return "INT";
|
||||
case TypeID::Real: return "REAL";
|
||||
case TypeID::Text: return "TEXT";
|
||||
case TypeID::Bool: return "BOOL";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue