Skip to content

Commit

Permalink
Added field references and fixed calls
Browse files Browse the repository at this point in the history
  • Loading branch information
trishume committed Apr 9, 2012
1 parent f10169a commit 9238306
Show file tree
Hide file tree
Showing 8 changed files with 74 additions and 6 deletions.
1 change: 1 addition & 0 deletions include/TuringParser/ASTTokens.h
Expand Up @@ -46,4 +46,5 @@ AST_TOKEN(BOOL_LITERAL) /* children: string: true or false */
AST_TOKEN(CALL) /* children: assignableExpr arg* string: */
AST_TOKEN(PTRDEREF) /* children: assignableExpr string: */
AST_TOKEN(FIELD_REF_OP) /* children: lhs string: rhs */
AST_TOKEN(POINTER_FIELD_REF_OP) /* children: lhs string: rhs */
AST_TOKEN(VAR_REFERENCE) /* children: string: var name */
3 changes: 3 additions & 0 deletions include/TuringParser/LexerTokens.h
Expand Up @@ -3,6 +3,8 @@

TURING_TKN(COMMA,comma)
TURING_TKN(COLON,colon)
TURING_TKN(HASH,hash)
TURING_TKN(EXCLAMATION,exclamation point)
TURING_TKN(BRACKET_O,opening parenthesis)
TURING_TKN(BRACKET_C,closing parenthesis)
TURING_TKN(SQUARE_BRACKET_O,opening square bracket)
Expand Down Expand Up @@ -37,6 +39,7 @@ TURING_TKN(OP_GT,> operator)
TURING_TKN(OP_GE,>= operator)
TURING_TKN(OP_LT,< operator)
TURING_TKN(OP_LE,<= operator)
TURING_TKN(OP_POINTER_FIELD_REF,-> operator)
TURING_TKN(OP_DOT,field reference operator)
TURING_TKN(DOTDOT,'..')
TURING_TKN(OP_AND,'and' operator)
Expand Down
6 changes: 5 additions & 1 deletion include/TuringParser/ParseErrors.h
Expand Up @@ -15,4 +15,8 @@ PARSE_ERROR(match_fail,"Expected %0; found %1.")
// args: unexpected token human name, unexpected token string
PARSE_ERROR(unexpected_token_in_expression,"Unexpected %0.")
// args: previous error, operator token human name
PARSE_ERROR(possible_missing_op_rhs,"%0 Perhaps the other side of the %1 is missing?")
PARSE_ERROR(possible_missing_op_rhs,"%0 In right side of %1.")
// args:
PARSE_ERROR(extra_comma_in_call,"Extra comma before the end of function call.")
// args: human name of offending token
PARSE_ERROR(no_identifier_in_field_ref,"%0 after field reference. Only identifiers can come after a field reference.")
3 changes: 3 additions & 0 deletions include/TuringParser/Token.h
Expand Up @@ -24,6 +24,9 @@ namespace OTParser {
SourceLoc getEnd() {
return Begin.advance(String.size());
}
SourceRange getRange() {
return SourceRange(Begin,getEnd());
}

//! \returns the name of a token. Or <UNKNOWN> for a bogus id.
static const char *getTokenName(Token::ID i);
Expand Down
11 changes: 10 additions & 1 deletion include/TuringParser/TuringParser.h
Expand Up @@ -20,7 +20,8 @@ namespace OTParser {
MULTIPLY, // *, /, div, mod, rem, shl, shr
PREFIX,
MODIFIER, // **, ^, #
CALL // calling is an operator
CALL, // calling is an operator
FIELDREF
};
}
//! A pratt Expression Parser for Turing
Expand Down Expand Up @@ -66,6 +67,14 @@ namespace OTParser {
Token token);
virtual int getPrecedence(Parser *parser);
};
//! parses field reference operators that only take
//! identifiers as right hand sides
class FieldRefParselet : public InfixOp {
public:
virtual ASTNode *parse(Parser *parser, ASTNode *left,
Token token);
virtual int getPrecedence(Parser *parser);
};
//! parses binary operators that can use the short assign
//! syntax. I.E +/+= div/div= shl/shl=
/*class PossibleAssignBinOp : public InfixOp {
Expand Down
6 changes: 6 additions & 0 deletions src/Lexer.cpp
Expand Up @@ -181,6 +181,8 @@ namespace OTParser {
case '\'': return stringOrCharLiteral(true);

case ',': consume(); return newToken(Token::COMMA, ",");
case '#': consume(); return newToken(Token::HASH, "#");
case '!': consume(); return newToken(Token::EXCLAMATION, "!");
case '(': consume(); return newToken(Token::BRACKET_O, "(");
case ')': consume(); return newToken(Token::BRACKET_C, ")");
case '[': consume(); return newToken(Token::SQUARE_BRACKET_O, "[");
Expand All @@ -205,6 +207,10 @@ namespace OTParser {
return numLiteral();
}
consume(); // if it is not a number we can consume the -
if (C == '>') {
consume();
return newToken(Token::OP_POINTER_FIELD_REF, "->");
}
return newToken(Token::OP_MINUS, "-");
case '/':
consume();
Expand Down
2 changes: 1 addition & 1 deletion src/Main.cpp
Expand Up @@ -40,7 +40,7 @@ void testLexer(std::string fileName) {

int main(int argc, char** argv)
{
SourceFile *f = new SourceFile("6*(7 + 4) - 7 div 6**6.0 < 8 xor 5 and true or false");
SourceFile *f = new SourceFile("6*(7 + 4) - Math.pow(7,9) div 6**6.0 < 8 xor variable.field->troll and true or false");
Lexer lex(f);
TuringParser parser(lex);

Expand Down
48 changes: 45 additions & 3 deletions src/TuringParser.cpp
@@ -1,5 +1,7 @@
#include "TuringParser/TuringParser.h"

#include "TuringParser/ParseError.h"

namespace OTParser {
TuringParser::TuringParser(Lexer lex) : Parser(lex) {
// -----------------------------------------------------------------
Expand All @@ -19,7 +21,8 @@ namespace OTParser {
// unary operators
registerPrefixOp(Token::OP_MINUS, new Parselet::UnaryOp(ASTNode::UNARY_OP));
registerPrefixOp(Token::OP_NOT, new Parselet::UnaryOp(ASTNode::UNARY_OP));
registerPrefixOp(Token::OP_DEREF, new Parselet::UnaryOp(ASTNode::UNARY_OP));
registerPrefixOp(Token::HASH, new Parselet::UnaryOp(ASTNode::UNARY_OP)); // type cheat operator
registerPrefixOp(Token::OP_DEREF, new Parselet::UnaryOp(ASTNode::PTRDEREF));
// -----------------------------------------------------------------
// register the infix parselets: Binary and postfix operators, calls
// -----------------------------------------------------------------
Expand Down Expand Up @@ -54,6 +57,9 @@ namespace OTParser {
registerInfixOp(Token::OP_EXPONENT, op);
op = new Parselet::CallParselet();
registerInfixOp(Token::BRACKET_O, op);
op = new Parselet::FieldRefParselet();
registerInfixOp(Token::OP_DOT, op);
registerInfixOp(Token::OP_POINTER_FIELD_REF, op);

}
TuringParser::~TuringParser() {
Expand Down Expand Up @@ -94,16 +100,52 @@ namespace OTParser {
node->addChild(left); // TODO check for callable expression?
// we may have no arguments, so check for an immediate )
if (parser->curTok().Type != Token::BRACKET_C) {
do {
node->addChild(parser->parseExpression()); // first argument
while (parser->curTok().Type == Token::COMMA) { // other args
parser->consume(); // consume comma
// extra comma like fun(hi,bob,)
if (parser->curTok().Type == Token::BRACKET_C) {
Token comma = parser->curTok();
ParseError err(comma.Begin,ParseError::extra_comma_in_call);
err.setEnd(comma.getEnd());
err.setHint(FixItHint::CreateRemoval(comma.getRange()));
throw err;
}
node->addChild(parser->parseExpression());
} while (parser->curTok().Type == Token::COMMA);
}
}
parser->match(Token::BRACKET_C);
return node;
}
int CallParselet::getPrecedence(Parser *parser) {
return Precedence::CALL;
}
ASTNode *FieldRefParselet::parse(Parser *parser, ASTNode *left, Token token) {
ASTNode *node = new ASTNode(ASTNode::FIELD_REF_OP,token.Begin);
bool isPointerRef = (token.Type == Token::OP_POINTER_FIELD_REF);

// TODO check for field reffable LHS?
if (isPointerRef) { // cheat, h->b is equivelant to ^h.b
ASTNode *deref = new ASTNode(ASTNode::PTRDEREF,token.Begin);
deref->addChild(left);
node->addChild(deref);
} else {
node->addChild(left);
}

Token tok = parser->consume();
if (tok.Type != Token::IDENTIFIER) {
ParseError err(tok.Begin,ParseError::no_identifier_in_field_ref);
err << Token::getHumanTokenName(tok.Type);
err.setEnd(tok.getEnd());
throw err;
}
node->str = tok.String; // field name
return node;
}
int FieldRefParselet::getPrecedence(OTParser::Parser *parser) {
return Precedence::FIELDREF;
}
/* Turing does not allow assignment as an expression but you can uncomment this and
use it if you want them.
ASTNode *PossibleAssignBinOp::parse(Parser *parser, ASTNode *left, Token token) {
Expand Down

0 comments on commit 9238306

Please sign in to comment.