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