Add pre scan and parsing expressions
This commit is contained in:
parent
921f9836b2
commit
4a7f2a8f88
@ -1,4 +1,4 @@
|
|||||||
/* global TokenType, ViewActivity, TextUtils */
|
/* global TokenType, ViewActivity, TextUtils, Variables, Operator */
|
||||||
|
|
||||||
function Parser(tokens) {
|
function Parser(tokens) {
|
||||||
this.tokens = tokens;
|
this.tokens = tokens;
|
||||||
@ -6,6 +6,11 @@ function Parser(tokens) {
|
|||||||
this.position = 0;
|
this.position = 0;
|
||||||
this.lastPosition = 0;
|
this.lastPosition = 0;
|
||||||
this.labels = {};
|
this.labels = {};
|
||||||
|
/** Оптимизация, чтобы каждый раз не искать endmenu/endif,
|
||||||
|
* если их попросту нет в необработанном сценарии */
|
||||||
|
this.hasEndMenu = false;
|
||||||
|
this.hasEndIf = false;
|
||||||
|
Variables.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
Parser.prototype.EOF = new Token("", TokenType.EOF);
|
Parser.prototype.EOF = new Token("", TokenType.EOF);
|
||||||
@ -212,27 +217,27 @@ Parser.prototype.command = function() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*if (this.match(token, TokenType.WORD)) {
|
if (this.match(token, TokenType.WORD)) {
|
||||||
if (this.match(TokenType.EQ)) {
|
if (this.match(TokenType.EQ)) {
|
||||||
// variable = expression
|
// variable = expression
|
||||||
Variables.setVariable(token.getText(), expression().eval());
|
Variables.setVariable(token.getText(), this.expression().eval());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (this.lookMatch(1, TokenType.EQ) && this.match(TokenType.PLUS)) {
|
if (this.lookMatch(1, TokenType.EQ) && this.match(TokenType.PLUS)) {
|
||||||
// variable += expression
|
// variable += expression
|
||||||
this.consume(TokenType.EQ);
|
this.consume(TokenType.EQ);
|
||||||
var varValue = Variables.getVariable(token.getText());
|
var varValue = Variables.getVariable(token.getText());
|
||||||
Variables.setVariable(token.getText(), varValue + expression().eval());
|
Variables.setVariable(token.getText(), varValue + this.expression().eval());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (this.lookMatch(1, TokenType.EQ) && this.match(TokenType.MINUS)) {
|
if (this.lookMatch(1, TokenType.EQ) && this.match(TokenType.MINUS)) {
|
||||||
// variable -= expression
|
// variable -= expression
|
||||||
this.consume(TokenType.EQ);
|
this.consume(TokenType.EQ);
|
||||||
var varValue = Variables.getVariable(token.getText());
|
var varValue = Variables.getVariable(token.getText());
|
||||||
Variables.setVariable(token.getText(), varValue - expression().eval());
|
Variables.setVariable(token.getText(), varValue - this.expression().eval());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
@ -312,6 +317,192 @@ Parser.prototype.playAmbience = function() {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Parser.prototype.expression = function() {
|
||||||
|
return this.orTest();
|
||||||
|
};
|
||||||
|
|
||||||
|
Parser.prototype.orTest = function() {
|
||||||
|
var expression = this.andTest();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (this.match(TokenType.OR)) {
|
||||||
|
expression = new BinaryExpression(Operator.BOOLEAN_OR, expression, this.andTest());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return expression;
|
||||||
|
};
|
||||||
|
|
||||||
|
Parser.prototype.andTest = function() {
|
||||||
|
var expression = this.notTest();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (this.match(TokenType.AND)) {
|
||||||
|
expression = new BinaryExpression(Operator.BOOLEAN_AND, expression, this.notTest());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return expression;
|
||||||
|
};
|
||||||
|
|
||||||
|
Parser.prototype.notTest = function() {
|
||||||
|
if (this.match(TokenType.NOT)) {
|
||||||
|
return new ValueExpression( this.notTest().eval() != 0 ? 0 : 1 );
|
||||||
|
}
|
||||||
|
return this.comparison();
|
||||||
|
};
|
||||||
|
|
||||||
|
Parser.prototype.comparison = function() {
|
||||||
|
var expression = this.additive();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (this.lookMatch(1, TokenType.EQ)) {
|
||||||
|
if (this.match(TokenType.EQ)) {
|
||||||
|
// ==
|
||||||
|
this.consume(TokenType.EQ);
|
||||||
|
expression = new BinaryExpression(Operator.EQUALS, expression, this.additive());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (this.match(TokenType.GT)) {
|
||||||
|
// >=
|
||||||
|
this.consume(TokenType.EQ);
|
||||||
|
expression = new BinaryExpression(Operator.GTEQ, expression, this.additive());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (this.match(TokenType.LT)) {
|
||||||
|
// <=
|
||||||
|
this.consume(TokenType.EQ);
|
||||||
|
expression = new BinaryExpression(Operator.LTEQ, expression, this.additive());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (this.match(TokenType.EXCL)) {
|
||||||
|
// !=
|
||||||
|
this.consume(TokenType.EQ);
|
||||||
|
expression = new BinaryExpression(Operator.NOTEQUALS, expression, this.additive());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.match(TokenType.LT)) {
|
||||||
|
expression = new BinaryExpression(Operator.LT, expression, this.additive());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (this.match(TokenType.GT)) {
|
||||||
|
expression = new BinaryExpression(Operator.GT, expression, this.additive());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return expression;
|
||||||
|
};
|
||||||
|
|
||||||
|
Parser.prototype.additive = function() {
|
||||||
|
var expression = this.unary();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (this.match(TokenType.PLUS)) {
|
||||||
|
expression = new BinaryExpression(Operator.ADD, expression, this.unary());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (this.match(TokenType.MINUS)) {
|
||||||
|
expression = new BinaryExpression(Operator.SUBTRACT, expression, this.unary());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return expression;
|
||||||
|
};
|
||||||
|
|
||||||
|
Parser.prototype.unary = function() {
|
||||||
|
if (this.match(TokenType.MINUS)) {
|
||||||
|
return new ValueExpression( -this.primary().eval() );
|
||||||
|
}
|
||||||
|
if (this.match(TokenType.PLUS)) {
|
||||||
|
return this.primary();
|
||||||
|
}
|
||||||
|
return this.primary();
|
||||||
|
};
|
||||||
|
|
||||||
|
Parser.prototype.primary = function() {
|
||||||
|
var current = this.get(0);
|
||||||
|
if (this.match(current, TokenType.NUMBER)) {
|
||||||
|
return new ValueExpression( parseFloat(current.getText()) );
|
||||||
|
}
|
||||||
|
if (this.match(current, TokenType.WORD)) {
|
||||||
|
return new VariableExpression(current.getText());
|
||||||
|
}
|
||||||
|
if (this.match(current, TokenType.LPAREN)) {
|
||||||
|
var expr = this.expression();
|
||||||
|
this.match(TokenType.RPAREN);
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
throw "Неизвестное выражение";
|
||||||
|
};
|
||||||
|
|
||||||
|
Parser.prototype.preScan = function() {
|
||||||
|
// Сканируем все метки, для быстрого перехода командой jump.
|
||||||
|
// А также определяем параметры для оптимизации.
|
||||||
|
for (var i = 0; i < this.tokensCount - 2; i++) {
|
||||||
|
var current = this.tokens[i].getType();
|
||||||
|
if (current === TokenType.ENDMENU) {
|
||||||
|
this.hasEndMenu = true;
|
||||||
|
} else if (current === TokenType.ENDIF) {
|
||||||
|
this.hasEndIf = true;
|
||||||
|
} else if ( (current === TokenType.LABEL) &&
|
||||||
|
(this.tokens[i + 2].getType() === TokenType.COLON) ) {
|
||||||
|
// label word :
|
||||||
|
var token = this.tokens[i + 1];
|
||||||
|
if (token.getType() === TokenType.WORD) {
|
||||||
|
// Добавляем позицию команды, следующей после метки.
|
||||||
|
this.labels[token.getText()] = i + 3;
|
||||||
|
}
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Parser.prototype.skipMenu = function() {
|
||||||
|
var pos = 0;
|
||||||
|
var level = 1; // уровень вложенности меню
|
||||||
|
while (true) {
|
||||||
|
// Расчёт уровня меню.
|
||||||
|
if (this.lookMatch(pos, TokenType.MENU) && this.lookMatch(pos + 1, TokenType.COLON)) {
|
||||||
|
level++;
|
||||||
|
pos += 2;
|
||||||
|
}
|
||||||
|
if (this.lookMatch(pos, TokenType.ENDMENU)) {
|
||||||
|
pos++;
|
||||||
|
level--;
|
||||||
|
// Завершаем работу по достижению ENDMENU первого уровня.
|
||||||
|
if (level <= 0) break;
|
||||||
|
}
|
||||||
|
if (this.lookMatch(pos, TokenType.EOF)) return 0;
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
return pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
Parser.prototype.skipIf = function() {
|
||||||
|
var pos = 0;
|
||||||
|
var level = 1;
|
||||||
|
while (true) {
|
||||||
|
if (this.lookMatch(pos, TokenType.IF)) level++;
|
||||||
|
else if (this.lookMatch(pos, TokenType.ENDIF)) {
|
||||||
|
pos++;
|
||||||
|
level--;
|
||||||
|
if (level <= 0) break;
|
||||||
|
} else if (this.lookMatch(pos, TokenType.EOF)) return 0;
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
return pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
Parser.prototype.consumeMusicName = function() {
|
Parser.prototype.consumeMusicName = function() {
|
||||||
var name = "";
|
var name = "";
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
function Views(parser) {
|
function Views(parser) {
|
||||||
this.parser = parser;
|
this.parser = parser;
|
||||||
|
parser.preScan();
|
||||||
|
|
||||||
this.windowTag = document.getElementById("window");
|
this.windowTag = document.getElementById("window");
|
||||||
this.textAuthorTag = document.getElementById("textAuthor");
|
this.textAuthorTag = document.getElementById("textAuthor");
|
||||||
|
Loading…
Reference in New Issue
Block a user