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:
Felix Queissner 2015-08-10 00:15:36 +02:00
parent cf148e411e
commit 832c9cf83a
10 changed files with 544 additions and 179 deletions

View file

@ -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 \

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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