Adds first version of IF ... THEN with block or single instruction support.
This commit is contained in:
parent
5a6be7e742
commit
b5b63b5817
6 changed files with 68 additions and 24 deletions
|
@ -39,7 +39,8 @@ DISTFILES += \
|
||||||
trainscript/trainscript.l \
|
trainscript/trainscript.l \
|
||||||
trainscript/file01.ts \
|
trainscript/file01.ts \
|
||||||
trainscript/Makefile \
|
trainscript/Makefile \
|
||||||
trainscript/trainscript.y
|
trainscript/trainscript.y \
|
||||||
|
trainscript/file02.ts
|
||||||
|
|
||||||
QMAKE_INCDIR =
|
QMAKE_INCDIR =
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ struct MethodBody
|
||||||
struct MethodDeclaration
|
struct MethodDeclaration
|
||||||
{
|
{
|
||||||
MethodHeader header;
|
MethodHeader header;
|
||||||
MethodBody *body;
|
trainscript::Instruction *body;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ExpressionList
|
struct ExpressionList
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
|
|
||||||
VAR temp : BOOL;
|
VAR res : INT;
|
||||||
|
|
||||||
PUB main(x : INT) → c : INT
|
PUB main(x : INT) → c : INT
|
||||||
BEGIN
|
BEGIN
|
||||||
(x =/= c) → temp;
|
factorial(10) → res;
|
||||||
x → c;
|
END
|
||||||
|
|
||||||
|
PUB factorial(number : INT) → result : INT
|
||||||
|
BEGIN
|
||||||
|
1 → result;
|
||||||
|
IF number > 1 THEN
|
||||||
|
number * factorial(number - 1) → result;
|
||||||
END
|
END
|
||||||
|
|
|
@ -47,6 +47,7 @@ BOOL { return KW_BOOL; }
|
||||||
BEGIN { return KW_BEGIN; }
|
BEGIN { return KW_BEGIN; }
|
||||||
END { return KW_END; }
|
END { return KW_END; }
|
||||||
IF { return KW_IF; }
|
IF { return KW_IF; }
|
||||||
|
THEN { return KW_THEN; }
|
||||||
ELSE { return KW_ELSE; }
|
ELSE { return KW_ELSE; }
|
||||||
REPEAT { return KW_REPEAT; }
|
REPEAT { return KW_REPEAT; }
|
||||||
FROM { return KW_FROM; }
|
FROM { return KW_FROM; }
|
||||||
|
|
|
@ -98,6 +98,7 @@ void yyerror(void *scanner, const char *s);
|
||||||
%token KW_END
|
%token KW_END
|
||||||
|
|
||||||
%token KW_IF
|
%token KW_IF
|
||||||
|
%token KW_THEN
|
||||||
%token KW_ELSE
|
%token KW_ELSE
|
||||||
%token KW_REPEAT
|
%token KW_REPEAT
|
||||||
%token KW_FROM
|
%token KW_FROM
|
||||||
|
@ -112,7 +113,7 @@ void yyerror(void *scanner, const char *s);
|
||||||
|
|
||||||
%type <method> method
|
%type <method> method
|
||||||
%type <methodHeader> methodDeclaration
|
%type <methodHeader> methodDeclaration
|
||||||
%type <body> block
|
%type <instruction> block
|
||||||
%type <body> body
|
%type <body> body
|
||||||
|
|
||||||
%type <local> argument
|
%type <local> argument
|
||||||
|
@ -141,20 +142,8 @@ input:
|
||||||
| input method {
|
| input method {
|
||||||
using namespace trainscript;
|
using namespace trainscript;
|
||||||
auto *mod = context->module;
|
auto *mod = context->module;
|
||||||
Block *body = new Block();
|
|
||||||
|
|
||||||
// Translate body here
|
Method *method = new Method(mod, $2.body);
|
||||||
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;
|
method->isPublic = $2.header.isPublic;
|
||||||
if($2.header.returnValue) {
|
if($2.header.returnValue) {
|
||||||
method->returnValue = std::pair<std::string, Variable>(
|
method->returnValue = std::pair<std::string, Variable>(
|
||||||
|
@ -184,12 +173,22 @@ method:
|
||||||
;
|
;
|
||||||
|
|
||||||
block:
|
block:
|
||||||
KW_BEGIN body KW_END { $$ = $2; }
|
KW_BEGIN body KW_END {
|
||||||
|
auto *block = new Block();
|
||||||
|
MethodBody *mb = $2;
|
||||||
|
while(mb) {
|
||||||
|
if(mb->instruction != nullptr) {
|
||||||
|
block->instructions.push_back(mb->instruction);
|
||||||
|
}
|
||||||
|
mb = mb->next;
|
||||||
|
}
|
||||||
|
$$ = block;
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
body:
|
body:
|
||||||
%empty { $$ = nullptr; }
|
%empty { $$ = nullptr; }
|
||||||
| body instruction SEMICOLON {
|
| body instruction {
|
||||||
auto *body = new MethodBody();
|
auto *body = new MethodBody();
|
||||||
body->indentation = 0;
|
body->indentation = 0;
|
||||||
body->instruction = $2;
|
body->instruction = $2;
|
||||||
|
@ -277,7 +276,8 @@ argument:
|
||||||
;
|
;
|
||||||
|
|
||||||
instruction:
|
instruction:
|
||||||
expression { $$ = $1; }
|
expression SEMICOLON { $$ = $1; }
|
||||||
|
| KW_IF expression KW_THEN instruction { $$ = new ConditionExpression($2, $4); }
|
||||||
;
|
;
|
||||||
|
|
||||||
expression:
|
expression:
|
||||||
|
|
|
@ -169,13 +169,13 @@ namespace trainscript
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Module *module;
|
Module *module;
|
||||||
Block *block;
|
Instruction *block;
|
||||||
bool isPublic;
|
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;
|
||||||
|
|
||||||
Method(Module *module, Block *block) : module(module), block(block)
|
Method(Module *module, Instruction *block) : module(module), block(block)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -391,4 +391,40 @@ namespace trainscript
|
||||||
return OP(left, right);
|
return OP(left, right);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ConditionExpression :
|
||||||
|
public Instruction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Instruction *condition;
|
||||||
|
Instruction *block;
|
||||||
|
|
||||||
|
ConditionExpression(Instruction *condition, Instruction *block) :
|
||||||
|
condition(condition),
|
||||||
|
block(block)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Variable execute(LocalContext &context) const override {
|
||||||
|
if(this->condition == nullptr) {
|
||||||
|
if(verbose) printf("IF: missing condition.\n");
|
||||||
|
return Variable::Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this->block == nullptr) {
|
||||||
|
return Variable::Void;
|
||||||
|
}
|
||||||
|
|
||||||
|
Variable result = this->condition->execute(context);
|
||||||
|
if(result.type != Type::Boolean) {
|
||||||
|
if(verbose) printf("IF: Invalid condition type.\n");
|
||||||
|
return Variable::Invalid;
|
||||||
|
}
|
||||||
|
if(result.boolean && (this->block != nullptr)) {
|
||||||
|
this->block->execute(context);
|
||||||
|
}
|
||||||
|
return Variable::Void;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue