#include "Parser.hpp" #include "Exception.hpp" #include "Tree.hpp" // This one is still a question: // [1 3' + 5] // Need: // Error reporting // // Done: // Reference counting for the tree? // strings (embedded quotes) // Comments // ... // Number recognition // Function handles // Keywords // Scripts // // [1 -2] --> [1 -2] // [1 - 2] --> [-1] // [1 - - 2] --> [3] // [1 - 2 - 3 -4] --> [-4 -4] // [1 - 2 - 3 - 4] --> -8 // [1 -2 - 3 -4] --> [1 -5 -4] // [- 3] --> [-3] // [2 -(3)] --> [2 -3] // [(2 -(3))] --> [-1] // [1 --2] --> [1 2] // // An additional set of cases to consider: // [A (3)] [A {4}] // both of which are incorrectly parsed as // [A(3)] and [A{4}] // // Question: // // if a +b print // // Suggestion.. if have unary operator followed by a nonwhitespace // tag it as a possible unary operator. // // Conclusion - if we have tight binding between the unary operators // // Conclusion - do not allow spaces after unary operators (unless you have to) // [a' 1 b'] --> [a',1,b'] // [a ' 1 b'] --> [a,' 1 b'] // [a ' 1 b] --> error // [a .' 1 b] --> error // Conclusion - do not allow spaces before transpose operators // [1 -3, 4] --> [1,-3,4] // Conclusion - spaces and commas are equivalent! // [a (3)] --> [a,3], not [a(3)] // [(a (3))] --> [a(3)] // Outside // fprintf('%d\n',a (3)) --> works as a(3) // // Special calls are causing more trouble... // // Consider: // foo /bar // Is this treated as an expression? or as a special function // call? // Also // foo bar.dat // causes trouble. // Now in general, if we have an identifier (outside a bracket) followed // by a character, it must be a special call. That takes care of the // above syntax. // // The only one missing case is the one described above. // bool HasNestedFunctions(const tree &root) { if (root.is(TOK_NEST_FUNC)) return true; for (int i=0;i lastpos) { lasterr = errmsg; lastpos = m_lex.ContextNum(); } throw ParseException(m_lex.ContextNum(),errmsg); } const Token & Parser::Expect(byte a) { const Token & ret(Next()); if (!m_lex.Next().Is(a)) { if (a != TOK_EOF) serror(string("Expecting ") + TokenToString(Token(a,0))); else serror(string("Unexpected input")); } else { Consume(); } return ret; } unsigned Parser::Precedence(const Token& t) { switch(t.Value()) { case TOK_SOR: return 1; case TOK_SAND: return 2; case '|': return 3; case '&': return 4; case '<': return 5; case '>': return 5; case TOK_LE : return 5; case TOK_GE: return 5; case TOK_EQ: return 5; case TOK_NE: return 5; case ':': return 6; case '+': return 7; case '-': return 7; case '*': return 8; case '/': return 8; case '\\': return 8; case TOK_DOTTIMES: return 8; case TOK_DOTRDIV: return 8; case TOK_DOTLDIV: return 8; case TOK_UNARY_PLUS: return 9; case TOK_UNARY_MINUS: return 9; case '~': return 9; case '^': return 10; case TOK_DOTPOWER: return 10; } return 1; } tree Parser::MatDef(byte basetok, byte closebracket) { m_lex.PushWSFlag(false); tree matdef(mkLeaf(basetok)); if (Match(TOK_SPACE)) Consume(); while (!Match(closebracket)) { tree rowdef(mkLeaf(TOK_ROWDEF,m_lex.ContextNum())); while (!Match(';') && !Match('\n') && !Match(closebracket)) { addChild(rowdef,Expression()); if (Match(',')) { Consume(); while (Match(TOK_SPACE)) Consume(); } else if (Match(TOK_SPACE)) Consume(); } if (Match(';') || Match('\n')) Consume(); if (Match(TOK_SPACE)) Consume(); addChild(matdef,rowdef); } m_lex.PopWSFlag(); return matdef; } tree Parser::TransposeFixup(tree base) { while ((Next().Value() == '\'') || (Next().Value() == TOK_DOTTRANSPOSE)) { base = mkNode(Next(),base); Consume(); } if (Match(TOK_SPACE)) if (!((m_lex.Peek(0,'-') || m_lex.Peek(0,'+')) && !m_lex.Peek(1,' '))) Consume(); return base; } tree Parser::AnonymousFunction() { unsigned pos1, pos2; pos1 = m_lex.ContextNum(); tree root(mkLeaf(TOK_ANONYMOUS_FUNC,m_lex.ContextNum())); Expect('('); tree args = mkLeaf(TOK_PARENS,m_lex.ContextNum()); while (!Match(')')) { addChild(args,Identifier()); if (!Match(')')) Expect(','); } Expect(')'); addChild(root,args); addChild(root,Expression()); pos2 = m_lex.ContextNum(); root.node().SetText("(" + m_lex.Snippet(pos1,pos2)); return root; } tree Parser::PrimaryExpression() { if (Next().IsUnaryOperator()) { Token opr(Next()); Consume(); if (Match(TOK_SPACE)) Consume(); if (opr.Is('+')) opr.SetValue(TOK_UNARY_PLUS); if (opr.Is('-')) opr.SetValue(TOK_UNARY_MINUS); unsigned q = Precedence(opr); tree child = Exp(q); tree root(mkNode(opr,child)); return root; } else if (Match('(')) { Consume(); m_lex.PushWSFlag(true); tree t = Exp(0); m_lex.PopWSFlag(); Expect(')'); return TransposeFixup(t); } else if (Match('@')) { tree root(mkLeaf(Next())); Consume(); if (Match('(')) addChild(root,AnonymousFunction()); else addChild(root,Identifier()); return TransposeFixup(root); } else if (MatchNumber() || Match(TOK_STRING)) { tree t = mkLeafWithLiterals(Next()); Consume(); return TransposeFixup(t); } else if (Match(TOK_END)) { return TransposeFixup(mkLeaf(Expect(TOK_END))); } else if (Match(TOK_IDENT)) { tree t = VariableDereference(); return TransposeFixup(t); } else if (Match('[')) { Consume(); tree t = MatDef(TOK_MATDEF,']'); Expect(']'); return TransposeFixup(t); } else if (Match('{')) { Consume(); tree t = MatDef(TOK_CELLDEF,'}'); Expect('}'); return TransposeFixup(t); } else { if (Match(')') || Match(']') || Match('}')) serror("mismatched parenthesis"); else serror("unrecognized token"); } } tree Parser::Exp(unsigned p) { tree t = PrimaryExpression(); while (Next().IsBinaryOperator() && (Precedence(Next()) >= p)) { Token opr_save(Next()); Consume(); if (Match(TOK_SPACE)) Consume(); unsigned q; if (opr_save.IsRightAssociative()) q = Precedence(opr_save); else q = 1+Precedence(opr_save); tree t1 = Exp(q); t = mkNode(opr_save,t,t1); } return t; } bool Parser::Match(byte a) { return m_lex.Next().Is(a); } void Parser::Consume() { m_lex.Consume(); } // NOTES - // There are still some issues here... // We need to introduce another tentative parse for functions // Consider the case: // function foo // statements // function hoo // function sub // end // end // end // The current code will parse foo into a function, // tree Parser::Process() { lastpos = 0; tree root; while (Match('\n')) Consume(); try { if (Match(TOK_FUNCTION)) { root = mkLeaf(TOK_FUNCTION_DEFS,m_lex.ContextNum()); while (Match(TOK_FUNCTION)) { tree child(FunctionDefinition()); addChild(root,child); while (Match('\n')) Consume(); } if (HasNestedFunctions(root) || Match(TOK_END)) Expect(TOK_END); while (Match('\n')) Consume(); while (Match(TOK_FUNCTION)) { addChild(root,FunctionDefinition()); if (HasNestedFunctions(root) || Match(TOK_END)) Expect(TOK_END); while (Match('\n')) Consume(); } } else { root = mkLeaf(TOK_SCRIPT,m_lex.ContextNum()); addChild(root,StatementList()); } } catch(ParseException &e) { throw Exception(LastErr() + m_lex.Context(LastPos())); } try { Expect(TOK_EOF); } catch (ParseException &e) { throw Exception("Unexpected input" + m_lex.Context()); } return root; } tree ParseString(string arg) { Scanner S(arg,""); Parser P(S); return P.StatementList(); } tree ParseExpressionString(string arg) { Scanner S(arg,""); Parser P(S); try { return P.Expression(); } catch(ParseException &e) { return tree(); } }