Files
BlitzNext/compiler/lib/parser.cpp
T

911 lines
21 KiB
C++
Raw Normal View History

2019-01-18 15:55:51 +01:00
#include "parser.hpp"
2019-01-18 17:04:57 +01:00
#include <cstdlib>
2019-01-19 18:28:07 +01:00
#include <fstream>
#include "ex.hpp"
#include "varnode.hpp"
#include <Windows.h>
#include <stdutil.hpp>
2014-01-31 08:23:00 +13:00
2019-01-18 17:04:57 +01:00
static const int TEXTLIMIT = 1024 * 1024 - 1;
2014-01-31 08:23:00 +13:00
2019-01-18 17:04:57 +01:00
enum { STMTS_PROG, STMTS_BLOCK, STMTS_LINE };
2014-01-31 08:23:00 +13:00
2019-01-18 17:04:57 +01:00
static bool isTerm(int c)
{
return c == ':' || c == '\n';
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:04:57 +01:00
Parser::Parser(Toker& t) : toker(&t), main_toker(&t) {}
2019-01-19 18:28:07 +01:00
std::shared_ptr<ProgNode> Parser::parse(const std::string& main)
2019-01-18 17:04:57 +01:00
{
incfile = main;
2019-01-19 18:28:07 +01:00
consts = std::make_shared<DeclSeqNode>();
structs = std::make_shared<DeclSeqNode>();
funcs = std::make_shared<DeclSeqNode>();
datas = std::make_shared<DeclSeqNode>();
std::shared_ptr<StmtSeqNode> stmts;
stmts = parseStmtSeq(STMTS_PROG);
if (toker->curr() != EOF) {
exp("end-of-file");
2014-01-31 08:23:00 +13:00
}
2019-01-19 18:28:07 +01:00
return std::make_shared<ProgNode>(consts, structs, funcs, datas, stmts);
2014-01-31 08:23:00 +13:00
}
2019-01-19 18:28:07 +01:00
void Parser::ex(const std::string& s)
2019-01-18 17:04:57 +01:00
{
2019-01-19 18:28:07 +01:00
throw BlitzException(s, toker->pos(), incfile);
2014-01-31 08:23:00 +13:00
}
2019-01-19 18:28:07 +01:00
void Parser::exp(const std::string& s)
2019-01-18 17:04:57 +01:00
{
switch (toker->curr()) {
case NEXT:
ex("'Next' without 'For'");
case WEND:
ex("'Wend' without 'While'");
case ELSE:
case ELSEIF:
ex("'Else' without 'If'");
case ENDIF:
ex("'Endif' without 'If'");
case ENDFUNCTION:
ex("'End Function' without 'Function'");
case UNTIL:
ex("'Until' without 'Repeat'");
case FOREVER:
ex("'Forever' without 'Repeat'");
case CASE:
ex("'Case' without 'Select'");
case ENDSELECT:
ex("'End Select' without 'Select'");
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:04:57 +01:00
ex("Expecting " + s);
2014-01-31 08:23:00 +13:00
}
2019-01-19 18:28:07 +01:00
std::string Parser::parseIdent()
2019-01-18 17:04:57 +01:00
{
if (toker->curr() != IDENT)
exp("identifier");
2019-01-19 18:28:07 +01:00
std::string t = toker->text();
2014-01-31 08:23:00 +13:00
toker->next();
return t;
}
2019-01-18 17:04:57 +01:00
void Parser::parseChar(int c)
{
if (toker->curr() != c)
2019-01-19 18:28:07 +01:00
exp(std::string("'") + char(c) + std::string("'"));
2014-01-31 08:23:00 +13:00
toker->next();
}
2019-01-19 18:28:07 +01:00
std::shared_ptr<StmtSeqNode> Parser::parseStmtSeq(int scope)
2019-01-18 17:04:57 +01:00
{
2019-01-19 18:28:07 +01:00
std::shared_ptr<StmtSeqNode> stmts = std::make_shared<StmtSeqNode>(incfile);
2019-01-18 17:04:57 +01:00
parseStmtSeq(stmts, scope);
2019-01-19 18:28:07 +01:00
return stmts;
2014-01-31 08:23:00 +13:00
}
2019-01-19 18:28:07 +01:00
void Parser::parseStmtSeq(std::shared_ptr<StmtSeqNode> stmts, int scope)
2019-01-18 17:04:57 +01:00
{
for (;;) {
2019-01-19 18:28:07 +01:00
while (toker->curr() == ':' || (scope != STMTS_LINE && toker->curr() == '\n')) {
2019-01-18 17:04:57 +01:00
toker->next();
2019-01-19 18:28:07 +01:00
}
2019-01-18 17:04:57 +01:00
StmtNode* result = 0;
2014-01-31 08:23:00 +13:00
2019-01-18 17:04:57 +01:00
int pos = toker->pos();
2014-01-31 08:23:00 +13:00
2019-01-18 17:04:57 +01:00
switch (toker->curr()) {
case INCLUDE: {
if (toker->next() != STRINGCONST)
exp("include filename");
2019-01-19 18:28:07 +01:00
std::string inc = toker->text();
2019-01-18 17:04:57 +01:00
toker->next();
inc = inc.substr(1, inc.size() - 2);
2014-01-31 08:23:00 +13:00
2019-01-18 17:04:57 +01:00
//WIN32 KLUDGE//
char buff[MAX_PATH], *p;
if (GetFullPathName(inc.c_str(), MAX_PATH, buff, &p))
inc = buff;
inc = tolower(inc);
2014-01-31 08:23:00 +13:00
2019-01-18 17:04:57 +01:00
if (included.find(inc) != included.end())
break;
2014-01-31 08:23:00 +13:00
2019-01-19 18:28:07 +01:00
std::ifstream i_stream(inc.c_str());
2019-01-18 17:04:57 +01:00
if (!i_stream.good())
ex("Unable to open include file");
2014-01-31 08:23:00 +13:00
2019-01-19 18:28:07 +01:00
std::swap(this->incfile, inc);
2014-01-31 08:23:00 +13:00
2019-01-19 18:28:07 +01:00
std::shared_ptr<Toker> i_toker = std::make_shared<Toker>(i_stream);
std::swap(this->toker, i_toker);
2014-01-31 08:23:00 +13:00
2019-01-18 17:04:57 +01:00
included.insert(incfile);
2014-01-31 08:23:00 +13:00
2019-01-19 18:28:07 +01:00
std::shared_ptr<StmtSeqNode> ss = parseStmtSeq(scope);
if (toker->curr() != EOF) {
2019-01-18 17:04:57 +01:00
exp("end-of-file");
2019-01-19 18:28:07 +01:00
}
2014-01-31 08:23:00 +13:00
2019-01-19 18:28:07 +01:00
result = new IncludeNode(incfile, ss);
2014-01-31 08:23:00 +13:00
2019-01-19 18:28:07 +01:00
std::swap(this->toker, i_toker);
std::swap(this->incfile, inc);
2019-01-18 17:04:57 +01:00
} break;
case IDENT: {
2019-01-19 18:28:07 +01:00
std::string ident = toker->text();
2019-01-18 17:04:57 +01:00
toker->next();
2019-01-19 18:28:07 +01:00
std::string tag = parseTypeTag();
2019-01-18 17:04:57 +01:00
if (arrayDecls.find(ident) == arrayDecls.end() && toker->curr() != '=' && toker->curr() != '\\'
&& toker->curr() != '[') {
//must be a function
ExprSeqNode* exprs;
if (toker->curr() == '(') {
//ugly lookahead for optional '()' around statement params
int nest = 1, k;
for (k = 1;; ++k) {
int c = toker->lookAhead(k);
if (isTerm(c))
ex("Mismatched brackets");
else if (c == '(')
++nest;
else if (c == ')' && !--nest)
break;
}
if (isTerm(toker->lookAhead(++k))) {
2014-01-31 08:23:00 +13:00
toker->next();
2019-01-18 17:04:57 +01:00
exprs = parseExprSeq();
if (toker->curr() != ')')
exp("')'");
2014-01-31 08:23:00 +13:00
toker->next();
2019-01-18 17:04:57 +01:00
} else
exprs = parseExprSeq();
} else
exprs = parseExprSeq();
CallNode* call = new CallNode(ident, tag, exprs);
result = new ExprStmtNode(call);
} else {
//must be a var
a_ptr<VarNode> var(parseVar(ident, tag));
if (toker->curr() != '=')
exp("variable assignment");
2014-01-31 08:23:00 +13:00
toker->next();
2019-01-18 17:04:57 +01:00
ExprNode* expr = parseExpr(false);
result = new AssNode(var.release(), expr);
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:04:57 +01:00
} break;
case IF: {
toker->next();
result = parseIf();
if (toker->curr() == ENDIF)
toker->next();
} break;
case WHILE: {
toker->next();
2019-01-19 18:28:07 +01:00
std::shared_ptr<ExprNode> expr = parseExpr(false);
std::shared_ptr<StmtSeqNode> stmts = parseStmtSeq(STMTS_BLOCK);
int pos = toker->pos();
2019-01-18 17:04:57 +01:00
if (toker->curr() != WEND)
exp("'Wend'");
toker->next();
2019-01-19 18:28:07 +01:00
result = new WhileNode(expr, stmts, pos);
2019-01-18 17:04:57 +01:00
} break;
case REPEAT: {
toker->next();
ExprNode* expr = 0;
a_ptr<StmtSeqNode> stmts(parseStmtSeq(STMTS_BLOCK));
int curr = toker->curr();
int pos = toker->pos();
if (curr != UNTIL && curr != FOREVER)
exp("'Until' or 'Forever'");
toker->next();
if (curr == UNTIL)
expr = parseExpr(false);
result = new RepeatNode(stmts.release(), expr, pos);
} break;
case SELECT: {
toker->next();
ExprNode* expr = parseExpr(false);
a_ptr<SelectNode> selNode(new SelectNode(expr));
for (;;) {
while (isTerm(toker->curr()))
2014-01-31 08:23:00 +13:00
toker->next();
2019-01-18 17:04:57 +01:00
if (toker->curr() == CASE) {
2014-01-31 08:23:00 +13:00
toker->next();
2019-01-18 17:04:57 +01:00
a_ptr<ExprSeqNode> exprs(parseExprSeq());
if (!exprs->size())
exp("expression sequence");
a_ptr<StmtSeqNode> stmts(parseStmtSeq(STMTS_BLOCK));
selNode->push_back(new CaseNode(exprs.release(), stmts.release()));
continue;
} else if (toker->curr() == DEFAULT) {
2014-01-31 08:23:00 +13:00
toker->next();
2019-01-18 17:04:57 +01:00
a_ptr<StmtSeqNode> stmts(parseStmtSeq(STMTS_BLOCK));
if (toker->curr() != ENDSELECT)
exp("'End Select'");
selNode->defStmts = stmts.release();
break;
} else if (toker->curr() == ENDSELECT) {
break;
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:04:57 +01:00
exp("'Case', 'Default' or 'End Select'");
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:04:57 +01:00
toker->next();
result = selNode.release();
} break;
case FOR: {
a_ptr<VarNode> var;
a_ptr<StmtSeqNode> stmts;
toker->next();
var = parseVar();
if (toker->curr() != '=')
exp("variable assignment");
if (toker->next() == EACH) {
toker->next();
2019-01-19 18:28:07 +01:00
std::string ident = parseIdent();
stmts = parseStmtSeq(STMTS_BLOCK);
int pos = toker->pos();
2019-01-18 17:04:57 +01:00
if (toker->curr() != NEXT)
exp("'Next'");
toker->next();
result = new ForEachNode(var.release(), ident, stmts.release(), pos);
} else {
a_ptr<ExprNode> from, to, step;
from = parseExpr(false);
if (toker->curr() != TO)
exp("'TO'");
toker->next();
to = parseExpr(false);
//step...
if (toker->curr() == STEP) {
toker->next();
step = parseExpr(false);
} else
step = new IntConstNode(1);
stmts = parseStmtSeq(STMTS_BLOCK);
int pos = toker->pos();
if (toker->curr() != NEXT)
exp("'Next'");
toker->next();
result = new ForNode(var.release(), from.release(), to.release(), step.release(), stmts.release(), pos);
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:04:57 +01:00
} break;
case EXIT: {
toker->next();
result = new ExitNode();
} break;
case GOTO: {
toker->next();
2019-01-19 18:28:07 +01:00
std::string t = parseIdent();
result = new GotoNode(t);
2019-01-18 17:04:57 +01:00
} break;
case GOSUB: {
toker->next();
2019-01-19 18:28:07 +01:00
std::string t = parseIdent();
result = new GosubNode(t);
2019-01-18 17:04:57 +01:00
} break;
case RETURN: {
toker->next();
result = new ReturnNode(parseExpr(true));
} break;
case BBDELETE: {
if (toker->next() == EACH) {
2014-01-31 08:23:00 +13:00
toker->next();
2019-01-19 18:28:07 +01:00
std::string t = parseIdent();
result = new DeleteEachNode(t);
2019-01-18 17:04:57 +01:00
} else {
ExprNode* expr = parseExpr(false);
result = new DeleteNode(expr);
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:04:57 +01:00
} break;
case INSERT: {
toker->next();
a_ptr<ExprNode> expr1(parseExpr(false));
if (toker->curr() != BEFORE && toker->curr() != AFTER)
exp("'Before' or 'After'");
bool before = toker->curr() == BEFORE;
toker->next();
a_ptr<ExprNode> expr2(parseExpr(false));
result = new InsertNode(expr1.release(), expr2.release(), before);
} break;
2014-01-31 08:23:00 +13:00
case READ:
2019-01-18 17:04:57 +01:00
do {
toker->next();
VarNode* var = parseVar();
StmtNode* stmt = new ReadNode(var);
stmt->pos = pos;
pos = toker->pos();
stmts->push_back(stmt);
} while (toker->curr() == ',');
2014-01-31 08:23:00 +13:00
break;
case RESTORE:
2019-01-18 17:04:57 +01:00
if (toker->next() == IDENT) {
result = new RestoreNode(toker->text());
toker->next();
} else
result = new RestoreNode("");
2014-01-31 08:23:00 +13:00
break;
case DATA:
2019-01-18 17:04:57 +01:00
if (scope != STMTS_PROG)
ex("'Data' can only appear in main program");
do {
2014-01-31 08:23:00 +13:00
toker->next();
2019-01-18 17:04:57 +01:00
ExprNode* expr = parseExpr(false);
datas->push_back(new DataDeclNode(expr));
} while (toker->curr() == ',');
2014-01-31 08:23:00 +13:00
break;
case TYPE:
2019-01-18 17:04:57 +01:00
if (scope != STMTS_PROG)
ex("'Type' can only appear in main program");
toker->next();
structs->push_back(parseStructDecl());
2014-01-31 08:23:00 +13:00
break;
case BBCONST:
2019-01-18 17:04:57 +01:00
if (scope != STMTS_PROG)
ex("'Const' can only appear in main program");
do {
toker->next();
consts->push_back(parseVarDecl(DECL_GLOBAL, true));
} while (toker->curr() == ',');
2014-01-31 08:23:00 +13:00
break;
case FUNCTION:
2019-01-18 17:04:57 +01:00
if (scope != STMTS_PROG)
ex("'Function' can only appear in main program");
toker->next();
funcs->push_back(parseFuncDecl());
2014-01-31 08:23:00 +13:00
break;
case DIM:
2019-01-18 17:04:57 +01:00
do {
2014-01-31 08:23:00 +13:00
toker->next();
2019-01-18 17:04:57 +01:00
StmtNode* stmt = parseArrayDecl();
stmt->pos = pos;
pos = toker->pos();
stmts->push_back(stmt);
} while (toker->curr() == ',');
2014-01-31 08:23:00 +13:00
break;
case LOCAL:
2019-01-18 17:04:57 +01:00
do {
2014-01-31 08:23:00 +13:00
toker->next();
2019-01-18 17:04:57 +01:00
DeclNode* d = parseVarDecl(DECL_LOCAL, false);
StmtNode* stmt = new DeclStmtNode(d);
stmt->pos = pos;
pos = toker->pos();
stmts->push_back(stmt);
} while (toker->curr() == ',');
2014-01-31 08:23:00 +13:00
break;
case GLOBAL:
2019-01-18 17:04:57 +01:00
if (scope != STMTS_PROG)
ex("'Global' can only appear in main program");
do {
2014-01-31 08:23:00 +13:00
toker->next();
2019-01-18 17:04:57 +01:00
DeclNode* d = parseVarDecl(DECL_GLOBAL, false);
StmtNode* stmt = new DeclStmtNode(d);
stmt->pos = pos;
pos = toker->pos();
stmts->push_back(stmt);
} while (toker->curr() == ',');
2014-01-31 08:23:00 +13:00
break;
2019-01-18 17:04:57 +01:00
case '.': {
toker->next();
2019-01-19 18:28:07 +01:00
std::string t = parseIdent();
result = new LabelNode(t, datas->size());
2019-01-18 17:04:57 +01:00
} break;
2014-01-31 08:23:00 +13:00
default:
return;
}
2019-01-18 17:04:57 +01:00
if (result) {
result->pos = pos;
stmts->push_back(result);
2014-01-31 08:23:00 +13:00
}
}
}
2019-01-19 18:28:07 +01:00
std::string Parser::parseTypeTag()
2019-01-18 17:04:57 +01:00
{
switch (toker->curr()) {
case '%':
toker->next();
return "%";
case '#':
toker->next();
return "#";
case '$':
toker->next();
return "$";
case '.':
toker->next();
return parseIdent();
2014-01-31 08:23:00 +13:00
}
return "";
}
2019-01-19 18:28:07 +01:00
std::shared_ptr<VarNode> Parser::parseVar()
2019-01-18 17:04:57 +01:00
{
2019-01-19 18:28:07 +01:00
std::string ident = parseIdent();
std::string tag = parseTypeTag();
2019-01-18 17:04:57 +01:00
return parseVar(ident, tag);
2014-01-31 08:23:00 +13:00
}
2019-01-19 18:28:07 +01:00
std::shared_ptr<VarNode> Parser::parseVar(const std::string& ident, const std::string& tag)
2019-01-18 17:04:57 +01:00
{
2014-01-31 08:23:00 +13:00
a_ptr<VarNode> var;
2019-01-18 17:04:57 +01:00
if (toker->curr() == '(') {
2014-01-31 08:23:00 +13:00
toker->next();
2019-01-18 17:04:57 +01:00
a_ptr<ExprSeqNode> exprs(parseExprSeq());
if (toker->curr() != ')')
exp("')'");
2014-01-31 08:23:00 +13:00
toker->next();
2019-01-18 17:04:57 +01:00
var = new ArrayVarNode(ident, tag, exprs.release());
} else
var = new IdentVarNode(ident, tag);
2014-01-31 08:23:00 +13:00
2019-01-18 17:04:57 +01:00
for (;;) {
if (toker->curr() == '\\') {
2014-01-31 08:23:00 +13:00
toker->next();
2019-01-19 18:28:07 +01:00
std::string ident = parseIdent();
std::string tag = parseTypeTag();
ExprNode* expr = new VarExprNode(var.release());
var = new FieldVarNode(expr, ident, tag);
2019-01-18 17:04:57 +01:00
} else if (toker->curr() == '[') {
2014-01-31 08:23:00 +13:00
toker->next();
2019-01-18 17:04:57 +01:00
a_ptr<ExprSeqNode> exprs(parseExprSeq());
if (exprs->exprs.size() != 1 || toker->curr() != ']')
exp("']'");
2014-01-31 08:23:00 +13:00
toker->next();
2019-01-18 17:04:57 +01:00
ExprNode* expr = new VarExprNode(var.release());
var = new VectorVarNode(expr, exprs.release());
} else {
2014-01-31 08:23:00 +13:00
break;
}
}
return var.release();
}
2019-01-19 18:28:07 +01:00
std::shared_ptr<DeclNode> Parser::parseVarDecl(int kind, bool constant)
2019-01-18 17:04:57 +01:00
{
2019-01-19 18:28:07 +01:00
int pos = toker->pos();
std::string ident = parseIdent();
std::string tag = parseTypeTag();
DeclNode* d;
2019-01-18 17:04:57 +01:00
if (toker->curr() == '[') {
if (constant)
ex("Blitz arrays may not be constant");
toker->next();
a_ptr<ExprSeqNode> exprs(parseExprSeq());
if (exprs->size() != 1 || toker->curr() != ']')
exp("']'");
toker->next();
d = new VectorDeclNode(ident, tag, exprs.release(), kind);
} else {
ExprNode* expr = 0;
if (toker->curr() == '=') {
toker->next();
expr = parseExpr(false);
} else if (constant)
ex("Constants must be initialized");
d = new VarDeclNode(ident, tag, kind, constant, expr);
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:04:57 +01:00
d->pos = pos;
d->file = incfile;
2014-01-31 08:23:00 +13:00
return d;
}
2019-01-19 18:28:07 +01:00
std::shared_ptr<DimNode> Parser::parseArrayDecl()
2019-01-18 17:04:57 +01:00
{
2019-01-19 18:28:07 +01:00
int pos = toker->pos();
std::string ident = parseIdent();
std::string tag = parseTypeTag();
2019-01-18 17:04:57 +01:00
if (toker->curr() != '(')
exp("'('");
toker->next();
a_ptr<ExprSeqNode> exprs(parseExprSeq());
if (toker->curr() != ')')
exp("')'");
if (!exprs->size())
ex("can't have a 0 dimensional array");
2014-01-31 08:23:00 +13:00
toker->next();
2019-01-18 17:04:57 +01:00
DimNode* d = new DimNode(ident, tag, exprs.release());
arrayDecls[ident] = d;
d->pos = pos;
2014-01-31 08:23:00 +13:00
return d;
}
2019-01-19 18:28:07 +01:00
std::shared_ptr<DeclNode> Parser::parseFuncDecl()
2019-01-18 17:04:57 +01:00
{
2019-01-19 18:28:07 +01:00
int pos = toker->pos();
std::string ident = parseIdent();
std::string tag = parseTypeTag();
2019-01-18 17:04:57 +01:00
if (toker->curr() != '(')
exp("'('");
a_ptr<DeclSeqNode> params(new DeclSeqNode());
if (toker->next() != ')') {
for (;;) {
params->push_back(parseVarDecl(DECL_PARAM, false));
if (toker->curr() != ',')
break;
2014-01-31 08:23:00 +13:00
toker->next();
}
2019-01-18 17:04:57 +01:00
if (toker->curr() != ')')
exp("')'");
2014-01-31 08:23:00 +13:00
}
toker->next();
2019-01-18 17:04:57 +01:00
a_ptr<StmtSeqNode> stmts(parseStmtSeq(STMTS_BLOCK));
if (toker->curr() != ENDFUNCTION)
exp("'End Function'");
StmtNode* ret = new ReturnNode(0);
ret->pos = toker->pos();
stmts->push_back(ret);
toker->next();
DeclNode* d = new FuncDeclNode(ident, tag, params.release(), stmts.release());
d->pos = pos;
d->file = incfile;
2014-01-31 08:23:00 +13:00
return d;
}
2019-01-19 18:28:07 +01:00
std::shared_ptr<DeclNode> Parser::parseStructDecl()
2019-01-18 17:04:57 +01:00
{
2019-01-19 18:28:07 +01:00
int pos = toker->pos();
std::string ident = parseIdent();
2019-01-18 17:04:57 +01:00
while (toker->curr() == '\n')
toker->next();
a_ptr<DeclSeqNode> fields(new DeclSeqNode());
while (toker->curr() == FIELD) {
do {
toker->next();
fields->push_back(parseVarDecl(DECL_FIELD, false));
} while (toker->curr() == ',');
while (toker->curr() == '\n')
toker->next();
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:04:57 +01:00
if (toker->curr() != ENDTYPE)
exp("'Field' or 'End Type'");
2014-01-31 08:23:00 +13:00
toker->next();
2019-01-18 17:04:57 +01:00
DeclNode* d = new StructDeclNode(ident, fields.release());
d->pos = pos;
d->file = incfile;
2014-01-31 08:23:00 +13:00
return d;
}
2019-01-19 18:28:07 +01:00
std::shared_ptr<IfNode> Parser::parseIf()
2019-01-18 17:04:57 +01:00
{
a_ptr<ExprNode> expr;
a_ptr<StmtSeqNode> stmts, elseOpt;
2014-01-31 08:23:00 +13:00
2019-01-18 17:04:57 +01:00
expr = parseExpr(false);
if (toker->curr() == THEN)
toker->next();
2014-01-31 08:23:00 +13:00
2019-01-18 17:04:57 +01:00
bool blkif = isTerm(toker->curr());
stmts = parseStmtSeq(blkif ? STMTS_BLOCK : STMTS_LINE);
2014-01-31 08:23:00 +13:00
2019-01-18 17:04:57 +01:00
if (toker->curr() == ELSEIF) {
int pos = toker->pos();
2014-01-31 08:23:00 +13:00
toker->next();
2019-01-18 17:04:57 +01:00
IfNode* ifnode = parseIf();
ifnode->pos = pos;
elseOpt = new StmtSeqNode(incfile);
elseOpt->push_back(ifnode);
} else if (toker->curr() == ELSE) {
2014-01-31 08:23:00 +13:00
toker->next();
2019-01-18 17:04:57 +01:00
elseOpt = parseStmtSeq(blkif ? STMTS_BLOCK : STMTS_LINE);
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:04:57 +01:00
if (blkif) {
if (toker->curr() != ENDIF)
exp("'EndIf'");
} else if (toker->curr() != '\n')
exp("end-of-line");
2014-01-31 08:23:00 +13:00
2019-01-18 17:04:57 +01:00
return new IfNode(expr.release(), stmts.release(), elseOpt.release());
2014-01-31 08:23:00 +13:00
}
2019-01-19 18:28:07 +01:00
std::shared_ptr<ExprSeqNode> Parser::parseExprSeq()
2019-01-18 17:04:57 +01:00
{
2019-01-19 18:28:07 +01:00
std::shared_ptr<ExprSeqNode> exprs = std::make_shared<ExprSeqNode>();
2019-01-18 17:04:57 +01:00
bool opt = true;
2019-01-19 18:28:07 +01:00
while (std::shared_ptr<ExprNode> e = parseExpr(opt)) {
2019-01-18 17:04:57 +01:00
exprs->push_back(e);
if (toker->curr() != ',')
break;
toker->next();
opt = false;
2014-01-31 08:23:00 +13:00
}
2019-01-19 18:28:07 +01:00
return exprs;
2014-01-31 08:23:00 +13:00
}
2019-01-19 18:28:07 +01:00
std::shared_ptr<ExprNode> Parser::parseExpr(bool opt)
2019-01-18 17:04:57 +01:00
{
if (toker->curr() == NOT) {
2014-01-31 08:23:00 +13:00
toker->next();
2019-01-19 18:28:07 +01:00
std::shared_ptr<ExprNode> expr = parseExpr1(false);
return std::make_shared<RelExprNode>('=', expr, std::make_shared<IntConstNode>(0));
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:04:57 +01:00
return parseExpr1(opt);
2014-01-31 08:23:00 +13:00
}
2019-01-19 18:28:07 +01:00
std::shared_ptr<ExprNode> Parser::parseExpr1(bool opt)
2019-01-18 17:04:57 +01:00
{
2019-01-19 18:28:07 +01:00
std::shared_ptr<ExprNode> rhs;
std::shared_ptr<ExprNode> lhs = parseExpr2(opt);
2019-01-18 17:04:57 +01:00
if (!lhs)
return 0;
for (;;) {
int c = toker->curr();
2019-01-19 18:28:07 +01:00
if (c != AND && c != OR && c != XOR) {
return lhs;
}
2019-01-18 17:04:57 +01:00
toker->next();
2019-01-19 18:28:07 +01:00
rhs = parseExpr2(false);
lhs = std::make_shared<BinExprNode>(c, lhs, rhs);
2014-01-31 08:23:00 +13:00
}
}
2019-01-19 18:28:07 +01:00
std::shared_ptr<ExprNode> Parser::parseExpr2(bool opt)
2019-01-18 17:04:57 +01:00
{
2019-01-19 18:28:07 +01:00
std::shared_ptr<ExprNode> rhs;
std::shared_ptr<ExprNode> lhs = parseExpr3(opt);
2019-01-18 17:04:57 +01:00
if (!lhs)
return 0;
for (;;) {
int c = toker->curr();
2019-01-19 18:28:07 +01:00
if (c != '<' && c != '>' && c != '=' && c != LE && c != GE && c != NE) {
return lhs;
}
2019-01-18 17:04:57 +01:00
toker->next();
2019-01-19 18:28:07 +01:00
rhs = parseExpr3(false);
lhs = std::make_shared<RelExprNode>(c, lhs, rhs);
2014-01-31 08:23:00 +13:00
}
}
2019-01-19 18:28:07 +01:00
std::shared_ptr<ExprNode> Parser::parseExpr3(bool opt)
2019-01-18 17:04:57 +01:00
{
2019-01-19 18:28:07 +01:00
std::shared_ptr<ExprNode> rhs;
std::shared_ptr<ExprNode> lhs = parseExpr4(opt);
2019-01-18 17:04:57 +01:00
if (!lhs)
return 0;
for (;;) {
int c = toker->curr();
2019-01-19 18:28:07 +01:00
if (c != '+' && c != '-') {
return lhs;
}
2019-01-18 17:04:57 +01:00
toker->next();
2019-01-19 18:28:07 +01:00
rhs = parseExpr4(false);
lhs = std::make_shared<ArithExprNode>(c, lhs, rhs);
2014-01-31 08:23:00 +13:00
}
}
2019-01-19 18:28:07 +01:00
std::shared_ptr<ExprNode> Parser::parseExpr4(bool opt)
2019-01-18 17:04:57 +01:00
{
2019-01-19 18:28:07 +01:00
std::shared_ptr<ExprNode> rhs;
std::shared_ptr<ExprNode> lhs = parseExpr5(opt);
2019-01-18 17:04:57 +01:00
if (!lhs)
return 0;
for (;;) {
int c = toker->curr();
2019-01-19 18:28:07 +01:00
if (c != SHL && c != SHR && c != SAR) {
return lhs;
}
2019-01-18 17:04:57 +01:00
toker->next();
2019-01-19 18:28:07 +01:00
rhs = parseExpr5(false);
lhs = std::make_shared<BinExprNode>(c, lhs, rhs);
2014-01-31 08:23:00 +13:00
}
}
2019-01-19 18:28:07 +01:00
std::shared_ptr<ExprNode> Parser::parseExpr5(bool opt)
2019-01-18 17:04:57 +01:00
{
2019-01-19 18:28:07 +01:00
std::shared_ptr<ExprNode> rhs;
std::shared_ptr<ExprNode> lhs = parseExpr6(opt);
if (!lhs) {
2019-01-18 17:04:57 +01:00
return 0;
2019-01-19 18:28:07 +01:00
}
2019-01-18 17:04:57 +01:00
for (;;) {
int c = toker->curr();
2019-01-19 18:28:07 +01:00
if (c != '*' && c != '/' && c != MOD) {
return lhs;
}
2019-01-18 17:04:57 +01:00
toker->next();
2019-01-19 18:28:07 +01:00
rhs = parseExpr6(false);
lhs = std::make_shared<ArithExprNode>(c, lhs, rhs);
2014-01-31 08:23:00 +13:00
}
}
2019-01-19 18:28:07 +01:00
std::shared_ptr<ExprNode> Parser::parseExpr6(bool opt)
2019-01-18 17:04:57 +01:00
{
2019-01-19 18:28:07 +01:00
std::shared_ptr<ExprNode> rhs;
std::shared_ptr<ExprNode> lhs = parseUniExpr(opt);
if (!lhs) {
return nullptr;
}
2019-01-18 17:04:57 +01:00
for (;;) {
int c = toker->curr();
2019-01-19 18:28:07 +01:00
if (c != '^') {
return lhs;
}
2019-01-18 17:04:57 +01:00
toker->next();
2019-01-19 18:28:07 +01:00
rhs = parseUniExpr(false);
lhs = std::make_shared<ArithExprNode>(c, lhs, rhs);
2014-01-31 08:23:00 +13:00
}
}
2019-01-19 18:28:07 +01:00
std::shared_ptr<ExprNode> Parser::parseUniExpr(bool opt)
2019-01-18 17:04:57 +01:00
{
2019-01-19 18:28:07 +01:00
std::shared_ptr<ExprNode> result;
std::string t;
2014-01-31 08:23:00 +13:00
2019-01-18 17:04:57 +01:00
int c = toker->curr();
switch (c) {
2014-01-31 08:23:00 +13:00
case BBINT:
2019-01-18 17:04:57 +01:00
if (toker->next() == '%')
toker->next();
result = parseUniExpr(false);
result = new CastNode(result, Type::int_type);
2014-01-31 08:23:00 +13:00
break;
case BBFLOAT:
2019-01-18 17:04:57 +01:00
if (toker->next() == '#')
toker->next();
result = parseUniExpr(false);
result = new CastNode(result, Type::float_type);
2014-01-31 08:23:00 +13:00
break;
case BBSTR:
2019-01-18 17:04:57 +01:00
if (toker->next() == '$')
toker->next();
result = parseUniExpr(false);
result = new CastNode(result, Type::string_type);
2014-01-31 08:23:00 +13:00
break;
case OBJECT:
2019-01-18 17:04:57 +01:00
if (toker->next() == '.')
toker->next();
t = parseIdent();
result = parseUniExpr(false);
result = new ObjectCastNode(result, t);
2014-01-31 08:23:00 +13:00
break;
case BBHANDLE:
toker->next();
2019-01-18 17:04:57 +01:00
result = parseUniExpr(false);
result = new ObjectHandleNode(result);
2014-01-31 08:23:00 +13:00
break;
case BEFORE:
toker->next();
2019-01-18 17:04:57 +01:00
result = parseUniExpr(false);
result = new BeforeNode(result);
2014-01-31 08:23:00 +13:00
break;
case AFTER:
toker->next();
2019-01-18 17:04:57 +01:00
result = parseUniExpr(false);
result = new AfterNode(result);
2014-01-31 08:23:00 +13:00
break;
2019-01-18 17:04:57 +01:00
case '+':
case '-':
case '~':
case ABS:
case SGN:
2014-01-31 08:23:00 +13:00
toker->next();
2019-01-18 17:04:57 +01:00
result = parseUniExpr(false);
if (c == '~') {
result = new BinExprNode(XOR, result, new IntConstNode(-1));
} else {
result = new UniExprNode(c, result);
2014-01-31 08:23:00 +13:00
}
break;
default:
2019-01-18 17:04:57 +01:00
result = parsePrimary(opt);
2014-01-31 08:23:00 +13:00
}
return result;
}
2019-01-19 18:28:07 +01:00
std::shared_ptr<ExprNode> Parser::parsePrimary(bool opt)
2019-01-18 17:04:57 +01:00
{
2014-01-31 08:23:00 +13:00
a_ptr<ExprNode> expr;
2019-01-19 18:28:07 +01:00
std::string t, ident, tag;
2019-01-18 17:04:57 +01:00
ExprNode* result = 0;
int n, k;
2014-01-31 08:23:00 +13:00
2019-01-18 17:04:57 +01:00
switch (toker->curr()) {
2014-01-31 08:23:00 +13:00
case '(':
toker->next();
2019-01-18 17:04:57 +01:00
expr = parseExpr(false);
if (toker->curr() != ')')
exp("')'");
2014-01-31 08:23:00 +13:00
toker->next();
2019-01-18 17:04:57 +01:00
result = expr.release();
2014-01-31 08:23:00 +13:00
break;
case BBNEW:
2019-01-18 17:04:57 +01:00
toker->next();
t = parseIdent();
result = new NewNode(t);
2014-01-31 08:23:00 +13:00
break;
case FIRST:
2019-01-18 17:04:57 +01:00
toker->next();
t = parseIdent();
result = new FirstNode(t);
2014-01-31 08:23:00 +13:00
break;
case LAST:
2019-01-18 17:04:57 +01:00
toker->next();
t = parseIdent();
result = new LastNode(t);
2014-01-31 08:23:00 +13:00
break;
case BBNULL:
2019-01-18 17:04:57 +01:00
result = new NullNode();
2014-01-31 08:23:00 +13:00
toker->next();
break;
case INTCONST:
2019-01-18 17:04:57 +01:00
result = new IntConstNode(atoi(toker->text()));
2014-01-31 08:23:00 +13:00
toker->next();
break;
case FLOATCONST:
2019-01-18 17:04:57 +01:00
result = new FloatConstNode(atof(toker->text()));
2014-01-31 08:23:00 +13:00
toker->next();
break;
case STRINGCONST:
2019-01-18 17:04:57 +01:00
t = toker->text();
result = new StringConstNode(t.substr(1, t.size() - 2));
2014-01-31 08:23:00 +13:00
toker->next();
break;
case BINCONST:
2019-01-18 17:04:57 +01:00
n = 0;
t = toker->text();
for (k = 1; k < t.size(); ++k)
n = (n << 1) | (t[k] == '1');
result = new IntConstNode(n);
2014-01-31 08:23:00 +13:00
toker->next();
break;
case HEXCONST:
2019-01-18 17:04:57 +01:00
n = 0;
t = toker->text();
for (k = 1; k < t.size(); ++k)
n = (n << 4) | (isdigit(t[k]) ? t[k] & 0xf : (t[k] & 7) + 9);
result = new IntConstNode(n);
2014-01-31 08:23:00 +13:00
toker->next();
break;
case PI:
2019-01-18 17:04:57 +01:00
result = new FloatConstNode(3.1415926535897932384626433832795f);
toker->next();
break;
2014-01-31 08:23:00 +13:00
case BBTRUE:
2019-01-18 17:04:57 +01:00
result = new IntConstNode(1);
toker->next();
break;
2014-01-31 08:23:00 +13:00
case BBFALSE:
2019-01-18 17:04:57 +01:00
result = new IntConstNode(0);
toker->next();
break;
2014-01-31 08:23:00 +13:00
case IDENT:
2019-01-18 17:04:57 +01:00
ident = toker->text();
toker->next();
tag = parseTypeTag();
if (toker->curr() == '(' && arrayDecls.find(ident) == arrayDecls.end()) {
2014-01-31 08:23:00 +13:00
//must be a func
toker->next();
2019-01-18 17:04:57 +01:00
a_ptr<ExprSeqNode> exprs(parseExprSeq());
if (toker->curr() != ')')
exp("')'");
2014-01-31 08:23:00 +13:00
toker->next();
2019-01-18 17:04:57 +01:00
result = new CallNode(ident, tag, exprs.release());
} else {
2014-01-31 08:23:00 +13:00
//must be a var
2019-01-18 17:04:57 +01:00
VarNode* var = parseVar(ident, tag);
result = new VarExprNode(var);
2014-01-31 08:23:00 +13:00
}
break;
default:
2019-01-18 17:04:57 +01:00
if (!opt)
exp("expression");
2014-01-31 08:23:00 +13:00
}
return result;
}