Skip to content

Commit 572d85f

Browse files
committed
Add basic support for function/sub definitions. Add support for object property access. Add higher-level error checks.
1 parent 137c842 commit 572d85f

File tree

1 file changed

+198
-49
lines changed

1 file changed

+198
-49
lines changed

vbmonkey.cpp

Lines changed: 198 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ struct Token
2828
LPAREN,
2929
RPAREN,
3030
PROPERTY_ACCESS,
31+
EQUALS,
3132
EOL
3233
} type;
3334

@@ -58,8 +59,9 @@ struct SingleToken {
5859
{ '*', Token::OP },
5960
{ '/', Token::OP },
6061
{ '%', Token::OP },
61-
{ '.', Token::PROPERTY_ACCESS },
62-
{ ',', Token::COMMA }//,
62+
{ '.', Token::OP },
63+
{ ',', Token::COMMA },
64+
{ '=', Token::EQUALS },
6365
// { '\n', Token::EOL }
6466
};
6567

@@ -216,20 +218,43 @@ namespace ast
216218
{
217219
public:
218220
Identifier(const std::string &name) : name_(name) {}
219-
std::string toString() { return "IDENTIFIER"; }
221+
std::string toString() { return std::string("IDENTIFIER (") + name_ + ")"; }
220222

221223
private:
222224
std::string name_;
223225
};
224226

227+
class PropertyAccess : public Expr
228+
{
229+
public:
230+
PropertyAccess(Expr *owner, Expr *property)
231+
: owner_(owner), property_(property) {}
232+
std::string toString()
233+
{
234+
return owner_->toString() + " " + property_->toString();
235+
}
236+
237+
private:
238+
Expr *owner_;
239+
Expr *property_;
240+
};
241+
225242
class Dim : public Node
226243
{
227244
public:
228-
Dim(const std::string &name) : name_(name) {}
229-
std::string toString() { return "DIM"; }
245+
Dim(const std::string &name, Expr *val)
246+
: name_(name), val_(val) {}
247+
std::string toString()
248+
{
249+
if(!val_)
250+
return "DIM";
251+
else
252+
return std::string("DIM ") + val_->toString();
253+
}
230254

231255
private:
232256
std::string name_;
257+
Expr *val_;
233258
};
234259

235260
class BinaryExpr : public Expr
@@ -249,7 +274,7 @@ namespace ast
249274
public:
250275
CallExpr(const std::string &callee, const std::vector<Expr *> &args)
251276
: callee_(callee), args_(args) {}
252-
std::string toString() { return "CALL"; }
277+
std::string toString() { return std::string("CALL (") + callee_ + ")"; }
253278

254279
private:
255280
std::string callee_;
@@ -259,26 +284,39 @@ namespace ast
259284
class Function : public Node
260285
{
261286
public:
262-
Function(const std::string &name, const std::vector<std::string> &args, Expr *body)
263-
: name_(name), args_(args), body_(body) {}
264-
std::string toString() { return std::string("FUNCTION\n") + " " + body_->toString(); }
287+
Function(const std::string &name,
288+
const std::vector<std::string> &args,
289+
const std::vector<Node *> &body,
290+
bool sub)
291+
: name_(name), args_(args), body_(body), sub_(sub) {}
292+
std::string toString()
293+
{
294+
std::string repr(sub_ ? "SUB\n" : "FUNCTION\n");
295+
for(unsigned int i = 0; i < body_.size(); i++)
296+
repr += " " + body_[i]->toString() + "\n";
297+
return repr;
298+
}
265299

266300
private:
267301
std::string name_;
268302
std::vector<std::string> args_;
269-
Expr *body_;
303+
std::vector<Node *> body_;
304+
bool sub_;
270305
};
271306
}
272307

273308
typedef std::list<Token *> TokenList;
274309
typedef TokenList::const_reverse_iterator TokenIt;
275310

311+
Token *currentToken(TokenIt &it, const TokenIt &end)
312+
{
313+
return it != end ? *it : NULL;
314+
}
315+
276316
Token *nextToken(TokenIt &it, const TokenIt &end)
277317
{
278318
it++;
279-
if(it != end)
280-
return *it;
281-
else return NULL;
319+
return currentToken(it, end);
282320
}
283321

284322
ast::Node *errorN(const char *str)
@@ -307,13 +345,27 @@ int opPrecedence(char op)
307345
binopPrecedence['%'] = 10;
308346
binopPrecedence['/'] = 40;
309347
binopPrecedence['*'] = 40; // highest.
348+
binopPrecedence['.'] = 1000;
310349
}
311350

312351
int precedence = binopPrecedence[op];
313352
if (precedence <= 0) return -1;
314353
return precedence;
315354
}
316355

356+
#define EXPECT_TOKEN(t, expected, func, error) \
357+
{ if(!t || t->type != expected) \
358+
return func(error); }
359+
360+
#define EXPECT_TOKEN_N(t, expected, error) \
361+
EXPECT_TOKEN(t, expected, errorN, error)
362+
363+
#define EXPECT_TOKEN_E(t, expected, error) \
364+
EXPECT_TOKEN(t, expected, errorE, error)
365+
366+
#define EXPECT_ANY_TOKEN(t, func, error) \
367+
{ if(!t) return func(error); }
368+
317369
ast::Expr *parseLiteral(TokenIt &it, const TokenIt &end)
318370
{
319371
ast::Expr *node = new ast::Literal((*it)->value);
@@ -325,50 +377,71 @@ ast::Expr *parseExpr(TokenIt &it, const TokenIt &end);
325377

326378
ast::Expr *parseParenExpr(TokenIt &it, const TokenIt &end)
327379
{
328-
nextToken(it, end);
380+
Token *current = nextToken(it, end);
329381
ast::Expr *node = parseExpr(it, end);
330-
if((*it)->type != Token::RPAREN)
331-
return errorE("Expected ')'");
382+
current = currentToken(it, end);
383+
EXPECT_TOKEN_E(current, Token::RPAREN, "Expected ')'");
332384

333385
nextToken(it, end);
334386
return node;
335387
}
336388

337-
ast::Expr *parseIdentifer(TokenIt &it, const TokenIt &end)
389+
ast::Expr *parseIdentifier(TokenIt &it, const TokenIt &end)
338390
{
339-
std::string identifier = (*it)->value;
340-
Token *current = nextToken(it, end);
341-
if(!current || current->type != Token::LPAREN)
391+
Token *current = currentToken(it, end);
392+
EXPECT_ANY_TOKEN(current, errorE, "Identifier expected");
393+
394+
std::string identifier = current->value;
395+
current = nextToken(it, end);
396+
if(!current || (current->type != Token::LPAREN &&
397+
current->type != Token::PROPERTY_ACCESS))
342398
return new ast::Identifier(identifier);
343399

344-
current = nextToken(it, end);
345-
std::vector<ast::Expr *> args;
346-
if(current->type != Token::RPAREN)
347-
while(1)
348-
{
349-
ast::Expr *arg = parseExpr(it, end);
350-
if(!arg) return NULL;
351-
args.push_back(arg);
400+
if(current->type == Token::LPAREN)
401+
{
402+
current = nextToken(it, end);
403+
EXPECT_ANY_TOKEN(current, errorE, "Expression or ')' expected");
404+
405+
std::vector<ast::Expr *> args;
406+
if(current->type != Token::RPAREN)
407+
while(1)
408+
{
409+
ast::Expr *arg = parseExpr(it, end);
410+
if(!arg) return NULL;
411+
args.push_back(arg);
352412

353-
current = *it;
413+
current = currentToken(it, end);
414+
EXPECT_ANY_TOKEN(current, errorE, "Expected ')' or ','");
354415

355-
if(current->type == Token::RPAREN)
356-
break;
357-
else if(current->type != Token::COMMA)
358-
return errorE("Expected ')' or ','");
416+
if(current->type == Token::RPAREN)
417+
break;
418+
else if(current->type != Token::COMMA)
419+
return errorE("Expected ')' or ','");
359420

360-
current = nextToken(it, end);
361-
}
421+
current = nextToken(it, end);
422+
}
362423

363-
nextToken(it, end);
364-
return new ast::CallExpr(identifier, args);
424+
nextToken(it, end);
425+
return new ast::CallExpr(identifier, args);
426+
}
427+
428+
current = nextToken(it, end);
429+
EXPECT_TOKEN_E(current, Token::IDENTIFIER, "Identifier expected after '.'");
430+
431+
ast::Expr *property = parseIdentifier(it, end);
432+
//if(!property)
433+
return errorE("Identifier expected after '.'");
434+
//return new ast::PropertyAccess(identifier, property);
365435
}
366436

367437
ast::Expr *parsePrimary(TokenIt &it, const TokenIt &end)
368438
{
369-
switch((*it)->type)
439+
Token *current = currentToken(it, end);
440+
EXPECT_ANY_TOKEN(current, errorE, "Expected a primary expression");
441+
442+
switch(current->type)
370443
{
371-
case Token::IDENTIFIER: return parseIdentifer(it, end);
444+
case Token::IDENTIFIER: return parseIdentifier(it, end);
372445
case Token::NUMBER: return parseLiteral(it, end);
373446
case Token::LPAREN: return parseParenExpr(it, end);
374447
default: return errorE("Unexpected token when expecting an expression");
@@ -378,18 +451,29 @@ ast::Expr *parsePrimary(TokenIt &it, const TokenIt &end)
378451
ast::Node *parseDim(TokenIt &it, const TokenIt &end)
379452
{
380453
Token *current = nextToken(it, end);
381-
382-
if(!current || current->type != Token::IDENTIFIER)
383-
return errorN("Expected identifier");
454+
EXPECT_TOKEN_N(current, Token::IDENTIFIER, "Expected identifier");
455+
456+
std::string name = current->value;
457+
458+
current = nextToken(it, end);
459+
//FIXME: Dim foo 5
460+
if(!current || current->type != Token::EQUALS)
461+
return new ast::Dim(name, NULL);
384462

385-
ast::Node *dim = new ast::Dim(current->value);
386463
nextToken(it, end);
387-
return dim;
464+
ast::Expr *val = parseExpr(it, end);
465+
if(!val)
466+
return errorN("Expected expression");
467+
468+
return new ast::Dim(name, val);
388469
}
389470

390471
ast::Node *parseStatement(TokenIt &it, const TokenIt &end)
391472
{
392-
switch((*it)->type)
473+
Token *current = currentToken(it, end);
474+
EXPECT_ANY_TOKEN(current, errorN, "Statement expected");
475+
476+
switch(current->type)
393477
{
394478
case Token::DIM: return parseDim(it, end);
395479
default: return parseExpr(it, end);
@@ -400,7 +484,9 @@ ast::Expr *parseBinOpRHS(int exprPrecendence, ast::Expr *lhs, TokenIt &it, const
400484
{
401485
while(1)
402486
{
403-
char binOp = it != end ? (*it)->value.c_str()[0] : 0;
487+
Token *current = currentToken(it, end);
488+
489+
char binOp = current ? current->value.c_str()[0] : 0;
404490
int precendence = opPrecedence(binOp);
405491
if(precendence < exprPrecendence)
406492
return lhs;
@@ -409,7 +495,9 @@ ast::Expr *parseBinOpRHS(int exprPrecendence, ast::Expr *lhs, TokenIt &it, const
409495
if(!rhs)
410496
return NULL;
411497

412-
int nextPrecedence = opPrecedence(it != end ? (*it)->value.c_str()[0] : 0);
498+
current = currentToken(it, end);
499+
500+
int nextPrecedence = opPrecedence(current ? current->value.c_str()[0] : 0);
413501
if(precendence < nextPrecedence)
414502
{
415503
rhs = parseBinOpRHS(precendence + 1, rhs, it, end);
@@ -429,6 +517,66 @@ ast::Expr *parseExpr(TokenIt &it, const TokenIt &end)
429517
return parseBinOpRHS(NULL, lhs, it, end);
430518
}
431519

520+
ast::Node *parseFunction(TokenIt &it, const TokenIt &end, bool sub)
521+
{
522+
Token *current = nextToken(it, end);
523+
EXPECT_TOKEN_N(current, Token::IDENTIFIER, "Expected function identifier");
524+
525+
std::string name = current->value;
526+
527+
current = nextToken(it, end);
528+
EXPECT_TOKEN_N(current, Token::LPAREN, "Expected '('");
529+
530+
std::vector<std::string> args;
531+
while(1)
532+
{
533+
current = nextToken(it, end);
534+
if(current && current->type == Token::IDENTIFIER)
535+
{
536+
args.push_back(current->value);
537+
current = nextToken(it, end);
538+
if(current->type == Token::RPAREN)
539+
break;
540+
EXPECT_TOKEN_N(current, Token::COMMA, "Expected ',' in arg list");
541+
}
542+
else break;
543+
}
544+
545+
EXPECT_TOKEN_N(current, Token::RPAREN, "Expected ')'");
546+
current = nextToken(it, end);
547+
std::vector<ast::Node *> body;
548+
while(1)
549+
{
550+
current = currentToken(it, end);
551+
EXPECT_ANY_TOKEN(current, errorN, "Statement or function end expected");
552+
553+
if(current->type == Token::END)
554+
break;
555+
556+
if(ast::Node *stmt = parseStatement(it, end))
557+
body.push_back(stmt);
558+
else return errorN("Statement or function end expected");
559+
}
560+
561+
current = nextToken(it, end);
562+
EXPECT_TOKEN_N(current, (sub ? Token::SUB : Token::FUNCTION),
563+
"Function end expected");
564+
565+
nextToken(it, end);
566+
567+
return new ast::Function(name, args, body, sub);
568+
}
569+
570+
ast::Node *parseTopLevel(TokenIt &it, const TokenIt &end)
571+
{
572+
switch((*it)->type)
573+
{
574+
case Token::FUNCTION: return parseFunction(it, end, false);
575+
case Token::SUB: return parseFunction(it, end, true);
576+
default: return parseStatement(it, end);
577+
}
578+
}
579+
432580
typedef std::list<ast::Node *> ASTNodeList;
433581
typedef ASTNodeList::reverse_iterator ASTNodeListIt;
434582

@@ -439,7 +587,7 @@ ASTNodeList *generateAST(const TokenList &tokens)
439587
TokenIt it = tokens.rbegin(), end = tokens.rend();
440588
while(it != end)
441589
{
442-
node = parseStatement(it, end);
590+
node = parseTopLevel(it, end);
443591
if(node)
444592
ast->push_back(node);
445593
else break;
@@ -473,6 +621,7 @@ int main(int /*argc*/, char */*argv*/[])
473621

474622
std::cin.clear();
475623
} while(tokens.size());
476-
624+
625+
std::cout << std::endl;
477626
return 0;
478627
}

0 commit comments

Comments
 (0)