Adds comparison operators and bool.

This commit is contained in:
Felix Queissner 2015-08-10 16:37:16 +02:00
parent 9c831134ae
commit 5a6be7e742
9 changed files with 214 additions and 50 deletions

View file

@ -1,5 +1,5 @@
# -fsanitize=address
CFLAGS=
CFLAGS=-g
CCFLAGS=$(CFLAGS) -std=c++11 -c
LFLAGS=$(CFLAGS) -o tsvm

View file

@ -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
View 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;

View file

@ -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");
}

View file

@ -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; }
*/

View file

@ -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) {
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);
}

View file

@ -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;
}
}
}
}

View file

@ -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;
}

View file

@ -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";
}
}