Adds REPEAT and WHILE loop.

This commit is contained in:
Felix Queissner 2015-08-12 14:13:49 +02:00
parent 908c0e2ff1
commit cf02215de8
4 changed files with 100 additions and 2 deletions

View file

@ -4,7 +4,8 @@ VAR res : INT;
PUB main(x : INT) c : INT PUB main(x : INT) c : INT
BEGIN BEGIN
# factorial(10) res; # factorial(10) res;
fibonacci(7) res; # fibonacci(7) res;
problem1(1000) res;
END END
PUB factorial(number : INT) result : INT PUB factorial(number : INT) result : INT
@ -25,3 +26,21 @@ BEGIN
ELSE ELSE
fibonacci(n - 1) + fibonacci(n - 2) f; fibonacci(n - 1) + fibonacci(n - 2) f;
END END
# If we list all the natural numbers below 10 that are
# multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of
# these multiples is 23.
# Find the sum of all the multiples of 3 or 5 below 1000.
PUB problem1(max : INT) r : INT | iter : INT
BEGIN
1 iter;
0 r;
WHILE iter < max DO
BEGIN
IF (iter % 5) = 0 THEN
r + iter r;
ELSEIF (iter % 3) = 0 THEN
r + iter r;
iter + 1 iter;
END
END

View file

@ -55,6 +55,7 @@ FROM { return KW_FROM; }
TO { return KW_TO; } TO { return KW_TO; }
UNTIL { return KW_UNTIL; } UNTIL { return KW_UNTIL; }
WHILE { return KW_WHILE; } WHILE { return KW_WHILE; }
DO { return KW_DO; }
[0-9]+\.[0-9]* { yylval->fval = atof(yytext); return REAL; } [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; }

View file

@ -106,6 +106,7 @@ void yyerror(void *scanner, const char *s);
%token KW_TO %token KW_TO
%token KW_UNTIL %token KW_UNTIL
%token KW_WHILE %token KW_WHILE
%token KW_DO
%type <type> typeName %type <type> typeName
%type <varDecl> variableDeclaration %type <varDecl> variableDeclaration
@ -128,6 +129,7 @@ void yyerror(void *scanner, const char *s);
%type <instruction> expression %type <instruction> expression
%type <instruction> condition %type <instruction> condition
%type <instruction> elseIfLoop %type <instruction> elseIfLoop
%type <instruction> loop
%type <expressions> expressionList %type <expressions> expressionList
@ -284,11 +286,16 @@ instruction:
block { $$ = $1; } block { $$ = $1; }
| expression SEMICOLON { $$ = $1; } | expression SEMICOLON { $$ = $1; }
| condition { $$ = $1; } | condition { $$ = $1; }
| loop { $$ = $1; }
;
loop:
KW_REPEAT instruction { $$ = new RepeatEndlessExpression($2); }
| KW_WHILE expression KW_DO instruction { $$ = new RepeatWhileExpression($2, $4); }
; ;
condition: condition:
KW_IF expression KW_THEN instruction elseIfLoop { $$ = new IfExpression($2, $4, $5); } KW_IF expression KW_THEN instruction elseIfLoop { $$ = new IfExpression($2, $4, $5); }
//| KW_IF expression KW_THEN instruction KW_ELSE instruction { $$ = new IfExpression($2, $4, $6); }
; ;
elseIfLoop: elseIfLoop:

View file

@ -428,4 +428,75 @@ namespace trainscript
return Variable::Void; return Variable::Void;
} }
}; };
class RepeatEndlessExpression :
public Instruction
{
public:
Instruction *block;
RepeatEndlessExpression(Instruction *block) :
block(block)
{
}
Variable execute(LocalContext &context) const override {
if(this->block == nullptr) {
if(verbose) printf("REPEAT: missing block.\n");
return Variable::Invalid;
}
while(true)
{
Variable result = this->block->execute(context);
(void)result;
}
return Variable::Void;
}
};
class RepeatWhileExpression :
public Instruction
{
public:
Instruction *condition;
Instruction *block;
RepeatWhileExpression(Instruction *condition, Instruction *block) :
condition(condition),
block(block)
{
}
Variable execute(LocalContext &context) const override {
if(this->condition == nullptr) {
if(verbose) printf("REPEAT: missing condition.\n");
return Variable::Invalid;
}
if(this->block == nullptr) {
if(verbose) printf("REPEAT: missing block.\n");
return Variable::Invalid;
}
while(true)
{
Variable cond = this->condition->execute(context);
if(cond.type != Type::Boolean) {
printf("REPEAT: Invalid expression type.\n");
return Variable::Invalid;
}
if(cond.boolean == false) {
break;
}
this->block->execute(context);
}
return Variable::Void;
}
};
} }