Adds functional execution unit. Lots of memory leaks. LOTS OF MEMORY LEAKS! also somehow working exection which is quite nice.
This commit is contained in:
parent
cf148e411e
commit
832c9cf83a
10 changed files with 544 additions and 179 deletions
|
@ -27,7 +27,8 @@ HEADERS += \
|
||||||
src/varargs.h \
|
src/varargs.h \
|
||||||
src/vmm.h \
|
src/vmm.h \
|
||||||
trainscript/common.h \
|
trainscript/common.h \
|
||||||
trainscript/tsvm.hpp
|
trainscript/tsvm.hpp \
|
||||||
|
trainscript/typeid.hpp
|
||||||
|
|
||||||
DISTFILES += \
|
DISTFILES += \
|
||||||
asm/intr_common_handler.S \
|
asm/intr_common_handler.S \
|
||||||
|
|
|
@ -4,17 +4,17 @@ YACC=bison
|
||||||
all: trainscript.tab.o lex.yy.o tsvm.o main.o
|
all: trainscript.tab.o lex.yy.o tsvm.o main.o
|
||||||
g++ -o tsvm lex.yy.o trainscript.tab.o tsvm.o main.o
|
g++ -o tsvm lex.yy.o trainscript.tab.o tsvm.o main.o
|
||||||
|
|
||||||
main.o: main.cpp tsvm.hpp
|
main.o: main.cpp tsvm.hpp common.h
|
||||||
g++ -std=c++11 -c main.cpp -o main.o
|
g++ -std=c++11 -c main.cpp -o main.o
|
||||||
|
|
||||||
tsvm.o: tsvm.cpp tsvm.hpp
|
tsvm.o: tsvm.cpp tsvm.hpp common.h
|
||||||
g++ -std=c++11 -c tsvm.cpp -o tsvm.o
|
g++ -std=c++11 -c tsvm.cpp -o tsvm.o
|
||||||
|
|
||||||
lex.yy.o: lex.yy.cpp
|
lex.yy.o: lex.yy.cpp tsvm.hpp common.h
|
||||||
g++ -c lex.yy.cpp -o lex.yy.o
|
g++ -std=c++11 -c lex.yy.cpp -o lex.yy.o
|
||||||
|
|
||||||
trainscript.tab.o: trainscript.tab.cpp
|
trainscript.tab.o: trainscript.tab.cpp tsvm.hpp common.h
|
||||||
g++ -c trainscript.tab.cpp -o trainscript.tab.o
|
g++ -std=c++11 -c trainscript.tab.cpp -o trainscript.tab.o
|
||||||
|
|
||||||
lex.yy.cpp: trainscript.l
|
lex.yy.cpp: trainscript.l
|
||||||
$(LEX) --header-file=trainscript.l.h trainscript.l
|
$(LEX) --header-file=trainscript.l.h trainscript.l
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#include "tsvm.hpp"
|
||||||
|
|
||||||
#define ECHO do { } while(0)
|
#define ECHO do { } while(0)
|
||||||
|
|
||||||
void yyerror(void *scanner, const char *s);
|
void yyerror(void *scanner, const char *s);
|
||||||
|
@ -19,10 +21,6 @@ void yyerror(void *scanner, const char *s);
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace trainscript {
|
|
||||||
class Module;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
char *buffer;
|
char *buffer;
|
||||||
|
@ -32,23 +30,40 @@ typedef struct
|
||||||
void *scanner;
|
void *scanner;
|
||||||
} ParserData;
|
} ParserData;
|
||||||
|
|
||||||
typedef enum
|
struct VariableDeclaration
|
||||||
{
|
{
|
||||||
tidUNKNOWN = 0,
|
|
||||||
tidVOID = 1,
|
|
||||||
tidINT = 2,
|
|
||||||
tidREAL = 3,
|
|
||||||
tidTEXT = 4,
|
|
||||||
} typeid_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
typeid_t type;
|
|
||||||
int pointer;
|
|
||||||
} type_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
type_t type;
|
|
||||||
char *name;
|
char *name;
|
||||||
} VariableDeclaration;
|
trainscript::Variable variable;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LocalVariable
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
trainscript::Variable variable;
|
||||||
|
LocalVariable *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MethodHeader
|
||||||
|
{
|
||||||
|
bool isPublic;
|
||||||
|
char *name;
|
||||||
|
LocalVariable *returnValue;
|
||||||
|
LocalVariable *locals;
|
||||||
|
LocalVariable *arguments;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MethodBody
|
||||||
|
{
|
||||||
|
int indentation;
|
||||||
|
trainscript::Instruction *instruction;
|
||||||
|
MethodBody *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MethodDeclaration
|
||||||
|
{
|
||||||
|
MethodHeader header;
|
||||||
|
MethodBody *body;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Variable declaration
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,19 @@
|
||||||
|
|
||||||
# Trainscript Test File
|
# Trainscript Test File
|
||||||
VAR global : INT;
|
VAR global : INT;
|
||||||
|
VAR other : REAL;
|
||||||
|
|
||||||
PUB main() → c : INT | a : INT, b : INT
|
PUB main(x : INT) → c : INT | a : INT, b : INT
|
||||||
10 → a;
|
10 → a;
|
||||||
helper() → b;
|
20 → b;
|
||||||
a + b → c;
|
a + b → global;
|
||||||
|
# helper() → b;
|
||||||
|
|
||||||
PRI helper() → result : INT
|
PRI helper() → result : INT
|
||||||
20 → result;
|
20 → result;
|
||||||
|
|
||||||
|
PRI arghelper(a0 : INT, a1 : INT, a2 : INT, a3 : INT)
|
||||||
|
x → global;
|
||||||
|
|
||||||
|
PRI lochelper() | l0 : INT, l1 : INT, l2 : INT, l3 : INT
|
||||||
|
x → global;
|
||||||
|
|
|
@ -46,16 +46,13 @@ int main(int argc, char** argv)
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This should be replaced by parsing.... :P
|
// Debug some stuff out:
|
||||||
{
|
for(auto &var : module->variables) {
|
||||||
Block *block = new Block(module);
|
printf("Variable: %s : %s = ",
|
||||||
|
var.first.c_str(),
|
||||||
block->instructions.push_back(new DebugInstruction(module, "hello world!"));
|
typeName(var.second->type.id));
|
||||||
block->instructions.push_back(new DebugVariableInstruction(module, "x"));
|
var.second->printval();
|
||||||
|
printf("\n");
|
||||||
Method *m = new Method(module, block);
|
|
||||||
m->arguments.push_back({"x", Variable(TypeID::Int)});
|
|
||||||
module->methods.insert({"main", m});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Method *scriptMain = module->method("main");
|
Method *scriptMain = module->method("main");
|
||||||
|
@ -64,7 +61,22 @@ int main(int argc, char** argv)
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
scriptMain->invoke({ Variable(15) });
|
printf("run...\n");
|
||||||
|
scriptMain->invoke({ mkvar(10) });
|
||||||
|
printf("done.\n");
|
||||||
|
|
||||||
|
// Debug some stuff out:
|
||||||
|
for(auto &var : module->variables) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ VOID { return KW_VOID; }
|
||||||
INT { return KW_INT; }
|
INT { return KW_INT; }
|
||||||
REAL { return KW_REAL; }
|
REAL { return KW_REAL; }
|
||||||
TEXT { return KW_TEXT; }
|
TEXT { return KW_TEXT; }
|
||||||
|
[0-9]+\.[0-9]+ { yylval->fval = atof(yytext); return REAL; }
|
||||||
[0-9]+ { yylval->ival = atoi(yytext); return INT; }
|
[0-9]+ { yylval->ival = atoi(yytext); return INT; }
|
||||||
[a-zA-Z0-9]+ { yylval->text = strdup(yytext); return IDENTIFIER; }
|
[a-zA-Z0-9]+ { yylval->text = strdup(yytext); return IDENTIFIER; }
|
||||||
. { yyerror(NULL, "illegal token"); }
|
. { yyerror(NULL, "illegal token"); }
|
||||||
|
@ -42,6 +43,6 @@ TEXT { return KW_TEXT; }
|
||||||
/*
|
/*
|
||||||
[0-9]+ { yylval.ival = atoi(yytext); return INT; }
|
[0-9]+ { yylval.ival = atoi(yytext); return INT; }
|
||||||
[a-zA-Z0-9]+ { yylval.sval = strdup(yytext); return STRING; }
|
[a-zA-Z0-9]+ { yylval.sval = strdup(yytext); return STRING; }
|
||||||
[0-9]+\.[0-9]+ { yylval->fval = atof(yytext); return FLOAT; }
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -4,6 +4,20 @@
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
|
#include "tsvm.hpp"
|
||||||
|
|
||||||
|
using namespace trainscript;
|
||||||
|
|
||||||
|
namespace trainscript {
|
||||||
|
namespace ops {
|
||||||
|
Variable add(Variable lhs, Variable rhs);
|
||||||
|
Variable subtract(Variable lhs, Variable rhs);
|
||||||
|
Variable multiply(Variable lhs, Variable rhs);
|
||||||
|
Variable divide(Variable lhs, Variable rhs);
|
||||||
|
Variable modulo(Variable lhs, Variable rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
typedef union YYSTYPE YYSTYPE;
|
typedef union YYSTYPE YYSTYPE;
|
||||||
|
|
||||||
// stuff from flex that bison needs to know about:
|
// stuff from flex that bison needs to know about:
|
||||||
|
@ -13,7 +27,6 @@ void yyerror(void *scanner, const char *s);
|
||||||
|
|
||||||
#define scanner context->scanner
|
#define scanner context->scanner
|
||||||
|
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%pure-parser
|
%pure-parser
|
||||||
|
@ -26,8 +39,13 @@ void yyerror(void *scanner, const char *s);
|
||||||
int ival;
|
int ival;
|
||||||
char *text;
|
char *text;
|
||||||
int indentation;
|
int indentation;
|
||||||
type_t type;
|
trainscript::Type type;
|
||||||
VariableDeclaration declaration;
|
VariableDeclaration varDecl;
|
||||||
|
MethodDeclaration method;
|
||||||
|
MethodBody *body;
|
||||||
|
MethodHeader methodHeader;
|
||||||
|
trainscript::Instruction *instruction;
|
||||||
|
LocalVariable *local;
|
||||||
}
|
}
|
||||||
|
|
||||||
%token TAB
|
%token TAB
|
||||||
|
@ -46,7 +64,7 @@ void yyerror(void *scanner, const char *s);
|
||||||
%token RARROW
|
%token RARROW
|
||||||
%token LARROW
|
%token LARROW
|
||||||
|
|
||||||
%token <fval> FLOAT
|
%token <fval> REAL
|
||||||
%token <ival> INT
|
%token <ival> INT
|
||||||
%token <text> IDENTIFIER
|
%token <text> IDENTIFIER
|
||||||
|
|
||||||
|
@ -59,72 +77,185 @@ void yyerror(void *scanner, const char *s);
|
||||||
%token KW_REAL
|
%token KW_REAL
|
||||||
%token KW_TEXT
|
%token KW_TEXT
|
||||||
|
|
||||||
%type <ival> expression
|
|
||||||
%type <type> typeName
|
%type <type> typeName
|
||||||
%type <declaration> variableDeclaration
|
%type <varDecl> variableDeclaration
|
||||||
%type <indentation> indentation
|
%type <indentation> indentation
|
||||||
|
|
||||||
|
%type <method> method
|
||||||
|
%type <methodHeader> methodDeclaration
|
||||||
|
%type <body> body
|
||||||
|
|
||||||
|
%type <local> argument
|
||||||
|
%type <local> arguments
|
||||||
|
%type <local> argumentList
|
||||||
|
|
||||||
|
%type <local> methodLocals
|
||||||
|
%type <local> methodLocalList
|
||||||
|
|
||||||
|
%type <instruction> instruction
|
||||||
|
%type <instruction> expression
|
||||||
|
|
||||||
%start input
|
%start input
|
||||||
|
|
||||||
%left PLUS MINUS MULTIPLY DIVIDE MODULO
|
%left PLUS MINUS MULTIPLY DIVIDE MODULO RARROW
|
||||||
|
|
||||||
%%
|
%%
|
||||||
input:
|
input:
|
||||||
%empty
|
%empty
|
||||||
| input variableDeclaration SEMICOLON { printf("decl %s as %d^%d\n", $2.name, $2.type.type, $2.type.pointer); }
|
| input variableDeclaration SEMICOLON {
|
||||||
| input method { printf("method declaration.\n"); }
|
context->module->variables.insert( { $2.name, new Variable($2.variable) } );
|
||||||
|
}
|
||||||
|
| input method {
|
||||||
|
using namespace trainscript;
|
||||||
|
auto *mod = context->module;
|
||||||
|
Block *body = new Block(mod);
|
||||||
|
|
||||||
|
// Translate body here
|
||||||
|
MethodBody *mb = $2.body;
|
||||||
|
while(mb) {
|
||||||
|
if(mb->instruction != nullptr) {
|
||||||
|
body->instructions.push_back(mb->instruction);
|
||||||
|
} else {
|
||||||
|
printf("invalid instruction in %s\n", $2.header.name);
|
||||||
|
}
|
||||||
|
mb = mb->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
Method *method = new Method(mod, body);
|
||||||
|
method->isPublic = $2.header.isPublic;
|
||||||
|
if($2.header.returnValue) {
|
||||||
|
method->returnValue = std::pair<std::string, Variable>(
|
||||||
|
$2.header.returnValue->name,
|
||||||
|
$2.header.returnValue->variable);
|
||||||
|
}
|
||||||
|
LocalVariable *local = $2.header.locals;
|
||||||
|
while(local) {
|
||||||
|
method->locals.insert( { local->name, local->variable } );
|
||||||
|
local = local->next;
|
||||||
|
}
|
||||||
|
LocalVariable *arg = $2.header.arguments;
|
||||||
|
while(arg) {
|
||||||
|
method->arguments.push_back( { arg->name, arg->variable } );
|
||||||
|
arg = arg->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
context->module->methods.insert( { $2.header.name, method } );
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
method:
|
method:
|
||||||
methodDeclaration body
|
methodDeclaration body {
|
||||||
|
$$.header = $1;
|
||||||
|
$$.body = $2;
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
body:
|
body:
|
||||||
%empty
|
%empty { $$ = nullptr; }
|
||||||
| body indentation assignment SEMICOLON { printf("Indent: %d\n", $2); }
|
| body indentation instruction SEMICOLON {
|
||||||
|
auto *body = new MethodBody();
|
||||||
|
body->indentation = $2;
|
||||||
|
body->instruction = $3;
|
||||||
|
if($1 == nullptr) {
|
||||||
|
$$ = body;
|
||||||
|
} else {
|
||||||
|
$$ = $1;
|
||||||
|
auto *it = $1;
|
||||||
|
while(it->next) { it = it->next; }
|
||||||
|
it->next = body;
|
||||||
|
}
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
methodDeclaration:
|
methodDeclaration:
|
||||||
KW_PUB IDENTIFIER LBRACKET argumentList RBRACKET methodLocals
|
KW_PUB IDENTIFIER LBRACKET arguments RBRACKET methodLocals {
|
||||||
| KW_PRI IDENTIFIER LBRACKET argumentList RBRACKET methodLocals
|
$$.isPublic = true;
|
||||||
| KW_PUB IDENTIFIER LBRACKET argumentList RBRACKET RARROW argument methodLocals
|
$$.arguments = $4;
|
||||||
| KW_PRI IDENTIFIER LBRACKET argumentList RBRACKET RARROW argument methodLocals
|
$$.locals = $6;
|
||||||
|
$$.returnValue = nullptr;
|
||||||
|
$$.name = $2;
|
||||||
|
}
|
||||||
|
| KW_PRI IDENTIFIER LBRACKET arguments RBRACKET methodLocals {
|
||||||
|
$$.isPublic = false;
|
||||||
|
$$.arguments = $4;
|
||||||
|
$$.locals = $6;
|
||||||
|
$$.returnValue = nullptr;
|
||||||
|
$$.name = $2;
|
||||||
|
}
|
||||||
|
| KW_PUB IDENTIFIER LBRACKET arguments RBRACKET RARROW argument methodLocals {
|
||||||
|
$$.isPublic = true;
|
||||||
|
$$.arguments = $4;
|
||||||
|
$$.locals = $8;
|
||||||
|
$$.returnValue = $7;
|
||||||
|
$$.name = $2;
|
||||||
|
}
|
||||||
|
| KW_PRI IDENTIFIER LBRACKET arguments RBRACKET RARROW argument methodLocals {
|
||||||
|
$$.isPublic = false;
|
||||||
|
$$.arguments = $4;
|
||||||
|
$$.locals = $8;
|
||||||
|
$$.returnValue = $7;
|
||||||
|
$$.name = $2;
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
methodLocals:
|
methodLocals:
|
||||||
%empty
|
%empty { $$ = nullptr; }
|
||||||
| PIPE methodLocalList
|
| PIPE methodLocalList { $$ = $2; }
|
||||||
;
|
;
|
||||||
|
|
||||||
methodLocalList:
|
methodLocalList:
|
||||||
argument
|
argument { $$ = $1; }
|
||||||
| methodLocalList COMMA argument
|
| methodLocalList COMMA argument {
|
||||||
|
auto *it = $1;
|
||||||
|
while(it->next) { it = it->next; }
|
||||||
|
it->next = $3;
|
||||||
|
$$ = $1;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
arguments:
|
||||||
|
%empty { $$ = nullptr; }
|
||||||
|
| argumentList { $$ = $1; }
|
||||||
|
;
|
||||||
|
|
||||||
argumentList:
|
argumentList:
|
||||||
%empty
|
argument { $$ = $1; }
|
||||||
| argument
|
| argumentList COMMA argument {
|
||||||
| argumentList COMMA argument
|
auto *it = $1;
|
||||||
|
while(it->next) { it = it->next; }
|
||||||
|
it->next = $3;
|
||||||
|
$$ = $1;
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
argument:
|
argument:
|
||||||
IDENTIFIER COLON typeName
|
IDENTIFIER COLON typeName {
|
||||||
|
$$ = new LocalVariable();
|
||||||
|
$$->name = $1;
|
||||||
|
$$->variable.type = $3;
|
||||||
|
$$->variable.integer = 0; // zero value
|
||||||
|
$$->next = nullptr;
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
assignment:
|
instruction:
|
||||||
expression RARROW IDENTIFIER { printf("%s := %d\n", $3, $1); }
|
expression { $$ = $1; }
|
||||||
|
;
|
||||||
|
|
||||||
expression:
|
expression:
|
||||||
INT { $$ = $1; }
|
INT { $$ = new ConstantExpression(context->module, mkvar($1)); }
|
||||||
| IDENTIFIER { printf("[access %s]", $1); $$ = 1; }
|
| REAL { $$ = new ConstantExpression(context->module, mkvar($1)); }
|
||||||
| IDENTIFIER LBRACKET expressionList RBRACKET { printf("[call %s]", $1); $$ = 1; }
|
// | TEXT { $$ = new ConstantExpression(context->module, mkvar($1)); }
|
||||||
|
| IDENTIFIER { $$ = new VariableExpression(context->module, $1); }
|
||||||
|
| IDENTIFIER LBRACKET expressionList RBRACKET { $$ = nullptr; yyerror(nullptr, "missing instruction."); }
|
||||||
| LBRACKET expression RBRACKET { $$ = $2; }
|
| LBRACKET expression RBRACKET { $$ = $2; }
|
||||||
| expression PLUS expression { $$ = $1 + $3; }
|
| expression PLUS expression { $$ = new ArithmeticExpression<trainscript::ops::add>(context->module, $1, $3); }
|
||||||
| expression MINUS expression { $$ = $1 - $3; }
|
| expression MINUS expression { $$ = nullptr; yyerror(nullptr, "missing instruction.");}
|
||||||
| expression MULTIPLY expression { $$ = $1 * $3; }
|
| expression MULTIPLY expression { $$ = nullptr; yyerror(nullptr, "missing instruction.");}
|
||||||
| expression DIVIDE expression { $$ = $1 / $3; }
|
| expression DIVIDE expression { $$ = nullptr; yyerror(nullptr, "missing instruction.");}
|
||||||
| expression MODULO expression { $$ = $1 % $3; }
|
| expression MODULO expression { $$ = nullptr; yyerror(nullptr, "missing instruction.");}
|
||||||
|
| expression RARROW IDENTIFIER { $$ = new VariableAssignmentExpression(context->module, $3, $1); }
|
||||||
;
|
;
|
||||||
|
|
||||||
expressionList:
|
expressionList:
|
||||||
|
@ -134,14 +265,18 @@ expressionList:
|
||||||
;
|
;
|
||||||
|
|
||||||
variableDeclaration:
|
variableDeclaration:
|
||||||
KW_VAR IDENTIFIER COLON typeName { $$.name = $2; $$.type = $4; }
|
KW_VAR IDENTIFIER COLON typeName {
|
||||||
|
$$.name = $2;
|
||||||
|
$$.variable.type = $4;
|
||||||
|
$$.variable.integer = 0; // Initialize with zeroes
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
typeName:
|
typeName:
|
||||||
KW_VOID { $$.type = tidVOID; $$.pointer = 0; }
|
KW_VOID { $$.id = TypeID::Void; $$.pointer = 0; }
|
||||||
| KW_INT { $$.type = tidINT; $$.pointer = 0; }
|
| KW_INT { $$.id = TypeID::Int; $$.pointer = 0; }
|
||||||
| KW_REAL { $$.type = tidREAL; $$.pointer = 0; }
|
| KW_REAL { $$.id = TypeID::Real; $$.pointer = 0; }
|
||||||
| KW_TEXT { $$.type = tidTEXT; $$.pointer = 0; }
|
| KW_TEXT { $$.id = TypeID::Text; $$.pointer = 0; }
|
||||||
| KW_PTR LBRACKET typeName RBRACKET { $$ = $3; $$.pointer++; }
|
| KW_PTR LBRACKET typeName RBRACKET { $$ = $3; $$.pointer++; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -157,5 +292,5 @@ indentation:
|
||||||
#include "trainscript.l.h"
|
#include "trainscript.l.h"
|
||||||
|
|
||||||
void yyerror(void *scanner, const char *s) {
|
void yyerror(void *scanner, const char *s) {
|
||||||
// printf("Error: %s\n", s);
|
printf("Error: %s\n", s);
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,4 +57,79 @@ namespace trainscript
|
||||||
delete val.second;
|
delete val.second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Variable Method::invoke(std::vector<Variable> arguments)
|
||||||
|
{
|
||||||
|
LocalContext context;
|
||||||
|
if(this->returnValue.second.type.usable()) {
|
||||||
|
context.insert({ this->returnValue.first, &this->returnValue.second });
|
||||||
|
}
|
||||||
|
if(arguments.size() != this->arguments.size()) {
|
||||||
|
printf("MECKER anzahl!\n");
|
||||||
|
return Variable();
|
||||||
|
}
|
||||||
|
for(size_t i = 0; i < this->arguments.size(); i++) {
|
||||||
|
if(this->arguments[i].second.type != arguments[i].type) {
|
||||||
|
printf("MECKER argtyp!\n");
|
||||||
|
return Variable();
|
||||||
|
}
|
||||||
|
context.insert({this->arguments[i].first, new Variable(arguments[i]) });
|
||||||
|
}
|
||||||
|
for(auto local : this->locals) {
|
||||||
|
context.insert({ local.first, new Variable(local.second) });
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this->block->execute(context);
|
||||||
|
|
||||||
|
return this->returnValue.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ops
|
||||||
|
{
|
||||||
|
Variable add(Variable lhs, Variable rhs)
|
||||||
|
{
|
||||||
|
switch(lhs.type.id) {
|
||||||
|
case TypeID::Int:return mkvar(lhs.integer + rhs.integer);
|
||||||
|
case TypeID::Real: return mkvar(lhs.real + rhs.real);
|
||||||
|
default: printf("addition not supported for %s.\n", typeName(lhs.type.id)); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Variable subtract(Variable lhs, Variable rhs)
|
||||||
|
{
|
||||||
|
switch(lhs.type.id) {
|
||||||
|
case TypeID::Int: return mkvar(lhs.integer - rhs.integer);
|
||||||
|
case TypeID::Real:return mkvar(lhs.real - rhs.real);
|
||||||
|
default: printf("subtraction not supported for %s.\n", typeName(lhs.type.id)); return mkvar(TypeID::Void);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Variable multiply(Variable lhs, Variable rhs)
|
||||||
|
{
|
||||||
|
switch(lhs.type.id) {
|
||||||
|
case TypeID::Int: return mkvar(lhs.integer * rhs.integer);
|
||||||
|
case TypeID::Real: return mkvar(lhs.real * rhs.real);
|
||||||
|
default: printf("multiplication not supported for %s.\n", typeName(lhs.type.id)); return mkvar(TypeID::Void);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Variable divide(Variable lhs, Variable rhs)
|
||||||
|
{
|
||||||
|
switch(lhs.type.id) {
|
||||||
|
case TypeID::Int: return mkvar(lhs.integer / rhs.integer);
|
||||||
|
case TypeID::Real: return mkvar(lhs.real / rhs.real);
|
||||||
|
default: printf("division not supported for %s.\n", typeName(lhs.type.id)); return mkvar(TypeID::Void);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Variable modulo(Variable lhs, Variable rhs)
|
||||||
|
{
|
||||||
|
switch(lhs.type.id) {
|
||||||
|
case TypeID::Int: return mkvar(lhs.integer % rhs.integer);
|
||||||
|
// case TypeID::Real: mkvar(lhs.real % rhs.real);
|
||||||
|
default: printf("modulo not supported for %s.\n", typeName(lhs.type.id)); return mkvar(TypeID::Void);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,9 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "common.h"
|
#include "typeid.hpp"
|
||||||
|
|
||||||
namespace trainscript
|
namespace trainscript
|
||||||
{
|
{
|
||||||
|
@ -18,24 +19,11 @@ namespace trainscript
|
||||||
char *data;
|
char *data;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class TypeID
|
|
||||||
{
|
|
||||||
Unknown = tidUNKNOWN,
|
|
||||||
Void = tidVOID,
|
|
||||||
Int = tidINT,
|
|
||||||
Real = tidREAL,
|
|
||||||
Text = tidTEXT
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Type
|
struct Type
|
||||||
{
|
{
|
||||||
TypeID id;
|
TypeID id;
|
||||||
int pointer;
|
int pointer;
|
||||||
|
|
||||||
Type() : id(TypeID::Unknown), pointer(0) { }
|
|
||||||
Type(TypeID id) : id(id), pointer(0) { }
|
|
||||||
Type(TypeID id, int pointer) : id(id), pointer(pointer) { }
|
|
||||||
|
|
||||||
Type reference() const {
|
Type reference() const {
|
||||||
return { id, pointer + 1 };
|
return { id, pointer + 1 };
|
||||||
}
|
}
|
||||||
|
@ -70,23 +58,40 @@ namespace trainscript
|
||||||
Text text;
|
Text text;
|
||||||
};
|
};
|
||||||
|
|
||||||
Variable() : type(TypeID::Unknown), integer(0) { }
|
void printval() const
|
||||||
|
{
|
||||||
explicit Variable(Type type) : type(type), integer(0) { }
|
switch(this->type.id) {
|
||||||
|
case TypeID::Int: printf("%d", this->integer); break;
|
||||||
explicit Variable(TypeID type) : type(type), integer(0) { }
|
case TypeID::Real: printf("%f", this->real); break;
|
||||||
|
default: printf("???"); break;
|
||||||
explicit Variable(Int integer) : type(TypeID::Int), integer(integer) { }
|
}
|
||||||
|
}
|
||||||
explicit Variable(Real real) : type(TypeID::Real), real(real) { }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline Variable mkvar(Type type) { return { type, 0 }; }
|
||||||
|
|
||||||
|
static inline Variable mkvar(TypeID type) { return { { type, 0 }, 0 }; }
|
||||||
|
|
||||||
|
static inline Variable mkvar(Int value) { return { { TypeID::Int, 0 }, value }; }
|
||||||
|
|
||||||
class Module;
|
class Module;
|
||||||
|
|
||||||
using LocalContext = std::map<std::string, Variable&>;
|
class LocalContext :
|
||||||
|
public std::map<std::string, Variable*>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int depth;
|
||||||
|
|
||||||
|
LocalContext() : depth(0) { }
|
||||||
|
|
||||||
|
void indent() {
|
||||||
|
for(int i = 0; i < depth; i++) printf(" ");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class Instruction
|
class Instruction
|
||||||
{
|
{
|
||||||
|
protected:
|
||||||
Module *module;
|
Module *module;
|
||||||
public:
|
public:
|
||||||
Instruction (Module *module) : module(module)
|
Instruction (Module *module) : module(module)
|
||||||
|
@ -96,7 +101,7 @@ namespace trainscript
|
||||||
|
|
||||||
virtual ~Instruction() { }
|
virtual ~Instruction() { }
|
||||||
|
|
||||||
virtual void execute(LocalContext &context) const = 0;
|
virtual Variable execute(LocalContext &context) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Block :
|
class Block :
|
||||||
|
@ -111,51 +116,11 @@ namespace trainscript
|
||||||
for(auto *instr : instructions) delete instr;
|
for(auto *instr : instructions) delete instr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void execute(LocalContext &context) const override {
|
Variable execute(LocalContext &context) const override {
|
||||||
for(auto *instr : instructions) {
|
for(auto *instr : instructions) {
|
||||||
instr->execute(context);
|
instr->execute(context);
|
||||||
}
|
}
|
||||||
}
|
return mkvar(TypeID::Void);
|
||||||
};
|
|
||||||
|
|
||||||
class DebugInstruction :
|
|
||||||
public Instruction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
std::string message;
|
|
||||||
|
|
||||||
DebugInstruction(Module *module, std::string msg) : Instruction(module), message(msg) { }
|
|
||||||
|
|
||||||
void execute(LocalContext &context) const override {
|
|
||||||
printf("debug: %s\n", message.c_str());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class DebugVariableInstruction :
|
|
||||||
public Instruction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
std::string variable;
|
|
||||||
|
|
||||||
DebugVariableInstruction(Module *module, std::string variable) : Instruction(module), variable(variable) { }
|
|
||||||
|
|
||||||
void execute(LocalContext &context) const override {
|
|
||||||
if(context.count(variable) > 0) {
|
|
||||||
auto &var = context.at(variable);
|
|
||||||
switch(var.type.id) {
|
|
||||||
case TypeID::Int:
|
|
||||||
printf("%s := %d\n", variable.c_str(), var.integer);
|
|
||||||
break;
|
|
||||||
case TypeID::Real:
|
|
||||||
printf("%s := %f\n", variable.c_str(), var.real);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printf("%s has unknown type.\n", variable.c_str());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
printf("variable %s not found.\n", variable.c_str());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -164,6 +129,7 @@ namespace trainscript
|
||||||
public:
|
public:
|
||||||
Module *module;
|
Module *module;
|
||||||
Block *block;
|
Block *block;
|
||||||
|
bool isPublic;
|
||||||
std::vector<std::pair<std::string, Variable>> arguments;
|
std::vector<std::pair<std::string, Variable>> arguments;
|
||||||
std::map<std::string, Variable> locals;
|
std::map<std::string, Variable> locals;
|
||||||
std::pair<std::string, Variable> returnValue;
|
std::pair<std::string, Variable> returnValue;
|
||||||
|
@ -173,32 +139,7 @@ namespace trainscript
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Variable invoke(std::vector<Variable> arguments)
|
Variable invoke(std::vector<Variable> arguments);
|
||||||
{
|
|
||||||
LocalContext context;
|
|
||||||
if(this->returnValue.second.type.usable()) {
|
|
||||||
context.insert({ this->returnValue.first, this->returnValue.second });
|
|
||||||
}
|
|
||||||
if(arguments.size() != this->arguments.size()) {
|
|
||||||
printf("MECKER anzahl!\n");
|
|
||||||
return Variable();
|
|
||||||
}
|
|
||||||
for(size_t i = 0; i < this->arguments.size(); i++) {
|
|
||||||
if(this->arguments[i].second.type != arguments[i].type) {
|
|
||||||
printf("MECKER argtyp!\n");
|
|
||||||
return Variable();
|
|
||||||
}
|
|
||||||
context.insert({this->arguments[i].first, arguments[i] });
|
|
||||||
}
|
|
||||||
for(auto local : this->locals) {
|
|
||||||
context.insert({ local.first, local.second });
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
this->block->execute(context);
|
|
||||||
|
|
||||||
return this->returnValue.second;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Module
|
class Module
|
||||||
|
@ -228,4 +169,158 @@ namespace trainscript
|
||||||
|
|
||||||
static Module *load(const char *text);
|
static Module *load(const char *text);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Instructions
|
||||||
|
|
||||||
|
class ConstantExpression :
|
||||||
|
public Instruction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Variable value;
|
||||||
|
ConstantExpression(Module *mod, Variable value) : Instruction(mod), value(value) { }
|
||||||
|
|
||||||
|
Variable execute(LocalContext &context) const override {
|
||||||
|
context.indent(); printf("constant: "); this->value.printval(); printf("\n");
|
||||||
|
return this->value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class VariableExpression :
|
||||||
|
public Instruction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string variableName;
|
||||||
|
VariableExpression(Module *mod, std::string variableName) : Instruction(mod), variableName(variableName) { }
|
||||||
|
|
||||||
|
Variable execute(LocalContext &context) const override {
|
||||||
|
context.indent(); printf("variable: %s\n", this->variableName.c_str());
|
||||||
|
if(context.count(this->variableName) > 0) {
|
||||||
|
return *context.at(this->variableName);
|
||||||
|
} else {
|
||||||
|
auto *var = this->module->variable(this->variableName.c_str());
|
||||||
|
if(var != nullptr) {
|
||||||
|
return *var;
|
||||||
|
} else {
|
||||||
|
printf("Variable not found: %s\n", this->variableName.c_str());
|
||||||
|
return mkvar(TypeID::Void);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class VariableAssignmentExpression :
|
||||||
|
public Instruction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string variableName;
|
||||||
|
Instruction *expression;
|
||||||
|
VariableAssignmentExpression(Module *mod, std::string variableName, Instruction *expression) :
|
||||||
|
Instruction(mod),
|
||||||
|
variableName(variableName),
|
||||||
|
expression(expression)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Variable execute(LocalContext &context) const override {
|
||||||
|
if(this->expression == nullptr) {
|
||||||
|
printf("Invalid instruction in assignment.\n");
|
||||||
|
return mkvar(TypeID::Void);
|
||||||
|
}
|
||||||
|
context.depth++;
|
||||||
|
Variable result = this->expression->execute(context);
|
||||||
|
context.depth--;
|
||||||
|
|
||||||
|
context.indent(); printf("assign "); result.printval(); printf(" to %s\n", this->variableName.c_str());
|
||||||
|
|
||||||
|
Variable *target = nullptr;
|
||||||
|
if(context.count(this->variableName) > 0) {
|
||||||
|
target = context.at(this->variableName);
|
||||||
|
} else {
|
||||||
|
target = this->module->variable(this->variableName.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(target == nullptr) {
|
||||||
|
printf("Variable not found: %s\n", this->variableName.c_str());
|
||||||
|
return mkvar(TypeID::Void);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(target->type != result.type) {
|
||||||
|
printf(
|
||||||
|
"Assignment does not match: %s → %s\n",
|
||||||
|
typeName(result.type.id),
|
||||||
|
this->variableName.c_str());
|
||||||
|
return mkvar(TypeID::Void);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(target->type.id) {
|
||||||
|
case TypeID::Int: target->integer = result.integer; break;
|
||||||
|
case TypeID::Real: target->real = result.real; break;
|
||||||
|
default: printf("assignment not supported.\n"); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
context.indent();
|
||||||
|
context.at("a")->printval();
|
||||||
|
printf(" ");
|
||||||
|
context.at("b")->printval();
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<Variable (*OP)(Variable, Variable)>
|
||||||
|
class ArithmeticExpression :
|
||||||
|
public Instruction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Instruction *rhs, *lhs;
|
||||||
|
|
||||||
|
ArithmeticExpression(Module *mod, Instruction *lhs, Instruction *rhs) :
|
||||||
|
Instruction(mod),
|
||||||
|
lhs(lhs),
|
||||||
|
rhs(rhs)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Variable execute(LocalContext &context) const override {
|
||||||
|
if(this->lhs == nullptr) {
|
||||||
|
printf("lhs: Invalid instruction in addition.\n");
|
||||||
|
return mkvar(TypeID::Void);
|
||||||
|
}
|
||||||
|
if(this->rhs == nullptr) {
|
||||||
|
printf("rhs: Invalid instruction in addition.\n");
|
||||||
|
return mkvar(TypeID::Void);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.depth++;
|
||||||
|
Variable left = this->lhs->execute(context);
|
||||||
|
Variable right = this->rhs->execute(context);
|
||||||
|
context.depth--;
|
||||||
|
|
||||||
|
if(left.type != right.type) {
|
||||||
|
printf(
|
||||||
|
"Arithmetic types do not match: %s != %s\n",
|
||||||
|
typeName(left.type.id),
|
||||||
|
typeName(right.type.id));
|
||||||
|
return mkvar(TypeID::Void);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.indent();
|
||||||
|
printf("Arithmetic on ");
|
||||||
|
left.printval();
|
||||||
|
printf(" and ");
|
||||||
|
right.printval();
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
return OP(left, right);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
23
trainscript/typeid.hpp
Normal file
23
trainscript/typeid.hpp
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace trainscript
|
||||||
|
{
|
||||||
|
enum class TypeID
|
||||||
|
{
|
||||||
|
Unknown = 0,
|
||||||
|
Void = 1,
|
||||||
|
Int = 2,
|
||||||
|
Real = 3,
|
||||||
|
Text = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *typeName(TypeID id) {
|
||||||
|
switch(id) {
|
||||||
|
case TypeID::Void: return "VOID";
|
||||||
|
case TypeID::Int: return "INT";
|
||||||
|
case TypeID::Real: return "REAL";
|
||||||
|
case TypeID::Text: return "TEXT";
|
||||||
|
default: return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue