You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdeedu/kturtle/src/parser.cpp

1085 lines
26 KiB

/*
Copyright (C) 2003 by Walter Schreppers
Copyright (C) 2004 by Cies Breijs
This program is free software; you can redistribute it and/or
modify it under the terms of version 2 of the GNU General Public
License as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
// This file is originally written by Walter Scheppers, but allmost
// allmost every aspect of it is heavily changed by Cies Breijs.
#include <tqstringlist.h>
#include <kdebug.h>
#include <tdelocale.h>
#include "parser.h"
Parser::Parser(TQTextIStream& in)
{
lexer = new Lexer(in);
tree = new TreeNode();
}
Parser::~Parser()
{
delete lexer;
}
void Parser::parse()
{
tree = Program(); // the first node that keeps the lexer running till finished/error
}
void Parser::getToken()
{
currentToken = lexer->lex(); // stores a Token, obtained though the lexer, in 'currentToken'
row = currentToken.start.row; // these will have to leave eventually, all should be passed on by the Token
col = currentToken.start.col;
kdDebug(0)<<"Parser::getToken(), got a token: '"<<currentToken.look<<"', @ ("<<currentToken.start.row<<", "<<currentToken.start.col<<") - ("<<currentToken.end.row<<", "<<currentToken.end.col<<"), tok-number:"<<currentToken.type<<endl;
}
TreeNode* Parser::Program()
{
Token emptyToken;
emptyToken.type = tokNotSet;
emptyToken.look = "";
emptyToken.start.row = 0;
emptyToken.start.col = 0;
emptyToken.end.row = 0;
emptyToken.end.col = 0;
TreeNode* program = new TreeNode(emptyToken, programNode, "program");
TreeNode* block = new TreeNode(emptyToken, blockNode, "block");
getToken();
// this is the main parse loop
kdDebug(0)<<"Parser::Program(): entering main parse loop..."<<endl;
while (currentToken.type != tokEOF) // currentToken.type returns the type of the currentToken
{
kdDebug(0)<<"Parser::Program(), [main parse loop]: looking for next statement..."<<endl;
block->appendChild( Statement() );
while (currentToken.type == tokEOL) getToken(); // newlines between statements are allowed
// runs statement related code, stores the returned TreeNode* in the nodetree
// note: Statement() allways gets a new Token with getToken() before it returns
}
program->appendChild(block);
kdDebug(0)<<"Parser::Program(): leaving main parse loop..."<<endl;
return program;
}
void Parser::matchToken(int expectedToken)
{
if (currentToken.type == expectedToken)
{
getToken(); // get a new token
return;
}
switch (expectedToken)
{
case tokEOL:
Error(currentToken, i18n("Unexpected intruction after the '%1' command, please use only one instruction per line").arg(preservedToken.look), 1010);
break;
case tokBegin:
Error(preservedToken, i18n("Expected '['"), 1010);
break;
case tokTo:
Error(currentToken, i18n("Expected 'to' after the '%1' command").arg(preservedToken.look), 1010);
break;
case tokAssign:
Error(currentToken, i18n("Expected '=' after the '%1' command").arg(preservedToken.look), 1010);
break;
case tokEnd:
Error(currentToken, i18n("Expected ']' after the '%1' command").arg(preservedToken.look), 1010);
break;
case tokUnknown:
Error(preservedToken, i18n("Expected a name after the '%1' command").arg(preservedToken.look), 1010);
break;
default:
Error(currentToken, i18n("UNDEFINED ERROR NR %1: please send this Logo script to the KTurtle developers").arg(expectedToken), 1010);
break;
}
}
void Parser::appendParameters(TreeNode* node)
{
node->appendChild( Expression() ); // append the first papameter
while (currentToken.type == tokComma)
{
matchToken(tokComma); // push through the comma
if (currentToken.type == tokEOL) return; // catch forgotten expressions, like "go 10, "
node->appendChild( Expression() );
}
}
TreeNode* Parser::getId()
{
TreeNode* n = new TreeNode(currentToken, idNode);
n->setLook(currentToken.look);
matchToken(tokUnknown); // Id's are ofcouse not yet known
return n;
}
TreeNode* Parser::FunctionCall(Token maybeFunctionCall)
{
kdDebug(0)<<"Parser::FunctionCall() [using identifier: '"<<maybeFunctionCall.look<<"']"<<endl;
TreeNode* fcall = new TreeNode(maybeFunctionCall, functionCallNode);
TreeNode* paramList = new TreeNode(currentToken, idListNode, "idlist");
// if (currentToken.type != tokEOL && currentToken.type != tokEOF)
if (currentToken.type == tokNumber ||
currentToken.type == tokString ||
currentToken.type == tokUnknown) // only if there is a possible parameter given after the call...
{
TreeNode* expr = Expression();
if (expr->getType() == Unknown) Error(currentToken, i18n("Expected an expression"), 1020);
else paramList->appendChild(expr);
while (currentToken.type == tokComma)
{
matchToken(tokComma);
expr = Expression();
if (expr->getType() == Unknown) Error(currentToken, i18n("Expected an expression"), 1020);
else paramList->appendChild(expr);
}
}
fcall->appendChild(paramList);
return fcall;
}
TreeNode* Parser::Factor()
{
TreeNode* node;
Token rememberedToken = currentToken;
switch (currentToken.type)
{
case tokBraceOpen:
matchToken(tokBraceOpen);
node = Expression();
matchToken(tokBraceClose);
break;
case tokUnknown:
node = getId();
if (learnedFunctionList.contains(rememberedToken.look) > 0) // is function call
{
delete node;
node = FunctionCall(rememberedToken);
node->setType(funcReturnNode); // expect returned value on stack
}
break;
case tokString:
node = new TreeNode(currentToken, constantNode);
{ // extra scope to localize the TQString 'str'
TQString str = currentToken.look;
if ( currentToken.look.endsWith("\"") )
{
// cut off the quotes and store the value
str.remove(0, 1).truncate( currentToken.look.length() - 2 );
}
else // problems but we need to keep it moving
{
str.remove(0, 1); // cut off the first quote only
Error(currentToken, i18n("String text not properly delimited with a ' \" ' (double quote)"), 1060);
}
node->setValue(str);
}
matchToken(tokString);
break;
case tokNumber:
node = new TreeNode(currentToken, constantNode);
node->setValue(currentToken.value);
matchToken(tokNumber);
break;
case tokRun:
node = ExternalRun();
break;
case tokInputWindow:
node = InputWindow();
break;
case tokRandom:
node = Random();
break;
case tokEOL:
node = new TreeNode(currentToken, Unknown);
break;
default:
TQString s = currentToken.look;
if ( s.isEmpty() || currentToken.type == tokEOF )
{
Error(currentToken, i18n("INTERNAL ERROR NR %1: please sent this Logo script to KTurtle developers").arg(1), 1020);
// if this error occurs the see the Parser::Repeat for the good solution using 'preservedToken'
}
else
{
Error(currentToken, i18n("Cannot understand '%1', expected an expression after the '%2' command").arg(s).arg(preservedToken.look), 1020);
}
node = new TreeNode(currentToken, Unknown);
getToken();
break;
}
return node;
}
TreeNode* Parser::signedFactor()
{
// see if there is a tokPlus, tokMinus or tokNot infront of the factor
TreeNode* node;
switch (currentToken.type)
{
case tokPlus:
matchToken(tokPlus);
return Factor();
break;
case tokMinus:
preservedToken = currentToken;
matchToken(tokMinus);
node = Factor();
if (node->getType() == constantNode)
{
// in case of just a constant (-3) situation
Value num = node->getValue();
num.setNumber( -num.Number() );
node->setValue(num);
return node;
}
else
{
// in case of a variable or other situation (-a)
TreeNode* minus = new TreeNode(preservedToken, minusNode);
minus->appendChild(node);
return minus;
}
break;
case tokNot:
preservedToken = currentToken;
matchToken(tokNot);
node = Factor();
{ // extra scope needed to localize not_Node
TreeNode* not_Node = new TreeNode(preservedToken, notNode);
not_Node->appendChild(node);
return not_Node;
}
break;
default:
// fall-through safety
return Factor();
break;
}
}
TreeNode* Parser::Term()
{
TreeNode* termNode = signedFactor();
TreeNode* pos = termNode;
TreeNode* left = NULL;
TreeNode* right = NULL;
while ( (currentToken.type == tokMul) || (currentToken.type == tokDev) || (currentToken.type == tokAnd) )
{
// while is is a multiplicative operator do...
left = pos;
pos = new TreeNode(currentToken, Unknown);
pos->appendChild(left);
switch (currentToken.type)
{
case tokMul:
matchToken(tokMul);
right = signedFactor();
pos->setType(mulNode);
break;
case tokDev:
matchToken(tokDev);
right = signedFactor();
pos->setType(divNode);
break;
case tokAnd:
matchToken(tokAnd);
right = signedFactor();
pos->setType(andNode);
break;
default:
Error(currentToken, i18n("Expected '*' or '/'"), 1030);
getToken();
return pos;
break;
}
if (right != NULL) pos->appendChild(right);
termNode = pos;
}
return termNode;
}
bool Parser::isAddOp(Token t)
{
return ( (t.type == tokPlus) ||
(t.type == tokMinus) ||
(t.type == tokGt) ||
(t.type == tokGe) ||
(t.type == tokLt) ||
(t.type == tokLe) ||
(t.type == tokEq) ||
(t.type == tokNe) ||
(t.type == tokOr) ||
(t.type == tokGe) );
}
/*---------------------------------------------------------------*/
/* Parse and Translate an Expression */
TreeNode* Parser::Expression()
{
TreeNode* retExp = Term(); // preset the base-TreeNode as it eventually will be returned
TreeNode* pos = retExp;
TreeNode* left = NULL;
TreeNode* right = NULL;
while ( isAddOp(currentToken) )
{
left = pos;
pos = new TreeNode(currentToken, Unknown);
pos->appendChild(left);
switch (currentToken.type)
{
case tokPlus:
matchToken(tokPlus);
right = Term();
pos->setType(addNode);
break;
case tokMinus:
matchToken(tokMinus);
right = Term();
pos->setType(subNode);
break;
case tokGt:
matchToken(tokGt);
right = Term();
pos->setType(nodeGT);
break;
case tokLt:
matchToken(tokLt);
right = Term();
pos->setType(nodeLT);
break;
case tokGe:
matchToken(tokGe);
right = Term();
pos->setType(nodeGE);
break;
case tokLe:
matchToken(tokLe);
right = Term();
pos->setType(nodeLE);
break;
case tokEq:
matchToken(tokEq);
right = Term();
pos->setType(nodeEQ);
break;
case tokNe:
matchToken(tokNe);
right = Term();
pos->setType(nodeNE);
break;
case tokOr:
matchToken(tokOr);
right = Term();
pos->setType(orNode);
break;
default:
Error(currentToken, i18n("Expected '*' or '/'"), 1040);
getToken();
return pos;
break;
}
if (right != NULL) pos->appendChild(right);
retExp = pos;
}
return retExp;
}
TreeNode* Parser::Assignment(Token t)
{
TreeNode* node = new TreeNode(t, assignNode);
matchToken(tokAssign); // match the '='
// the child is the expression or RHV of assignment
TreeNode* expr = NULL;
// if (currentToken.type == tokUnknown) expr = Other(); // in case of an functioncall
// else expr = Expression(); -------> fuctioncalls get caught in Expression() and co.
expr = Expression();
node->appendChild(expr);
return node;
}
TreeNode* Parser::Statement()
{
kdDebug(0)<<"Parser::Statement()"<<endl;
while (currentToken.type == tokEOL) getToken(); // statements can allways start on newlines
switch (currentToken.type)
{
case tokLearn : return Learn(); break;
case tokIf : return If(); break;
case tokFor : return For(); break;
case tokForEach : return ForEach(); break;
case tokWhile : return While(); break;
case tokRun : return ExternalRun(); break;
case tokReturn : return Return(); break;
case tokBreak : return Break(); break;
case tokUnknown : return Other(); break; //assignment or function call
case tokClear : return Clear(); break;
case tokGo : return Go(); break;
case tokGoX : return GoX(); break;
case tokGoY : return GoY(); break;
case tokForward : return Forward(); break;
case tokBackward : return Backward(); break;
case tokDirection : return Direction(); break;
case tokTurnLeft : return TurnLeft(); break;
case tokTurnRight : return TurnRight(); break;
case tokCenter : return Center(); break;
case tokSetPenWidth : return SetPenWidth(); break;
case tokPenUp : return PenUp(); break;
case tokPenDown : return PenDown(); break;
case tokSetFgColor : return SetFgColor(); break;
case tokSetBgColor : return SetBgColor(); break;
case tokResizeCanvas : return ResizeCanvas(); break;
case tokSpriteShow : return SpriteShow(); break;
case tokSpriteHide : return SpriteHide(); break;
case tokSpritePress : return SpritePress(); break;
case tokSpriteChange : return SpriteChange(); break;
case tokPrint : return Print(); break;
case tokInputWindow : return InputWindow(); break;
case tokMessage : return Message(); break;
case tokFontType : return FontType(); break;
case tokFontSize : return FontSize(); break;
case tokRepeat : return Repeat(); break;
case tokRandom : return Random(); break;
case tokWait : return Wait(); break;
case tokWrapOn : return WrapOn(); break;
case tokWrapOff : return WrapOff(); break;
case tokReset : return Reset(); break;
case tokEOF : return EndOfFile(); break;
case tokEnd : Error(currentToken, i18n("Cannot understand ']'"), 1050);
getToken();
return new TreeNode(currentToken, Unknown);
break;
case tokBegin : Error(currentToken, i18n("Cannot understand '['"), 1050);
getToken();
return new TreeNode(currentToken, Unknown);
break;
default : break;
}
if (currentToken.type != tokEnd)
{
Error(currentToken, i18n("Cannot understand '%1'").arg(currentToken.look), 1060);
}
getToken();
return new TreeNode(currentToken, Unknown); // fall-though for unknowns
}
TreeNode* Parser::Block()
{
TreeNode* block = new TreeNode(currentToken, blockNode, "block");
while (currentToken.type == tokEOL) getToken(); // skip newlines
matchToken(tokBegin);
while (currentToken.type == tokEOL) getToken(); // skip newlines
while ( (currentToken.type != tokEnd) && (currentToken.type != tokEOF) )
{
block->appendChild( Statement() );
while (currentToken.type == tokEOL) getToken(); // blocks can have newlines between their statements
}
matchToken(tokEnd);
return block;
}
//
// Turtle Funktions
//
// Functions that take NO arguments
TreeNode* Parser::Clear()
{
TreeNode* node = new TreeNode(currentToken, ClearNode);
preservedToken = currentToken;
getToken();
matchToken(tokEOL);
return node;
}
TreeNode* Parser::Center()
{
TreeNode* node = new TreeNode(currentToken, CenterNode);
preservedToken = currentToken;
getToken();
matchToken(tokEOL);
return node;
}
TreeNode* Parser::PenUp()
{
TreeNode* node = new TreeNode(currentToken, PenUpNode);
preservedToken = currentToken;
getToken();
matchToken(tokEOL);
return node;
}
TreeNode* Parser::PenDown()
{
TreeNode* node = new TreeNode(currentToken, PenDownNode);
preservedToken = currentToken;
getToken();
matchToken(tokEOL);
return node;
}
TreeNode* Parser::SpriteShow()
{
TreeNode* node = new TreeNode(currentToken, SpriteShowNode);
preservedToken = currentToken;
getToken();
matchToken(tokEOL);
return node;
}
TreeNode* Parser::SpriteHide()
{
TreeNode* node = new TreeNode(currentToken, SpriteHideNode);
preservedToken = currentToken;
getToken();
matchToken(tokEOL);
return node;
}
TreeNode* Parser::SpritePress()
{
TreeNode* node = new TreeNode(currentToken, SpritePressNode);
preservedToken = currentToken;
getToken();
matchToken(tokEOL);
return node;
}
TreeNode* Parser::WrapOn()
{
TreeNode* node = new TreeNode(currentToken, WrapOnNode);
preservedToken = currentToken;
getToken();
matchToken(tokEOL);
return node;
}
TreeNode* Parser::WrapOff()
{
TreeNode* node = new TreeNode(currentToken, WrapOffNode);
preservedToken = currentToken;
getToken();
matchToken(tokEOL);
return node;
}
TreeNode* Parser::Reset()
{
TreeNode* node = new TreeNode(currentToken, ResetNode);
preservedToken = currentToken;
getToken();
matchToken(tokEOL);
return node;
}
// Functions that take 1 arguments
TreeNode* Parser::GoX()
{
TreeNode* node = new TreeNode(currentToken, GoXNode);
preservedToken = currentToken;
getToken();
appendParameters(node);
matchToken(tokEOL);
return node;
}
TreeNode* Parser::GoY()
{
TreeNode* node = new TreeNode(currentToken, GoYNode);
preservedToken = currentToken;
getToken();
appendParameters(node);
matchToken(tokEOL);
return node;
}
TreeNode* Parser::Forward()
{
TreeNode* node = new TreeNode(currentToken, ForwardNode);
preservedToken = currentToken;
getToken();
appendParameters(node);
matchToken(tokEOL);
return node;
}
TreeNode* Parser::Backward()
{
TreeNode* node = new TreeNode(currentToken, BackwardNode);
preservedToken = currentToken;
getToken();
appendParameters(node);
matchToken(tokEOL);
return node;
}
TreeNode* Parser::Direction()
{
TreeNode* node = new TreeNode(currentToken, DirectionNode);
preservedToken = currentToken;
getToken();
appendParameters(node);
matchToken(tokEOL);
return node;
}
TreeNode* Parser::TurnLeft()
{
TreeNode* node = new TreeNode(currentToken, TurnLeftNode);
preservedToken = currentToken;
getToken();
appendParameters(node);
matchToken(tokEOL);
return node;
}
TreeNode* Parser::TurnRight()
{
TreeNode* node = new TreeNode(currentToken, TurnRightNode);
preservedToken = currentToken;
getToken();
appendParameters(node);
matchToken(tokEOL);
return node;
}
TreeNode* Parser::SetPenWidth()
{
TreeNode* node = new TreeNode(currentToken, SetPenWidthNode);
preservedToken = currentToken;
getToken();
appendParameters(node);
matchToken(tokEOL);
return node;
}
TreeNode* Parser::Message()
{
TreeNode* node = new TreeNode(currentToken, MessageNode);
preservedToken = currentToken;
getToken();
appendParameters(node);
matchToken(tokEOL);
return node;
}
TreeNode* Parser::InputWindow()
{
TreeNode* node = new TreeNode(currentToken, InputWindowNode);
preservedToken = currentToken;
getToken();
node->appendChild( Expression() );
// matchToken(tokEOL); this command can return values so can be used as expression/parameter
return node;
}
TreeNode* Parser::SpriteChange()
{
TreeNode* node = new TreeNode(currentToken, SpriteChangeNode);
preservedToken = currentToken;
getToken();
appendParameters(node);
matchToken(tokEOL);
return node;
}
TreeNode* Parser::FontType()
{
TreeNode* node = new TreeNode(currentToken, FontTypeNode);
preservedToken = currentToken;
getToken();
appendParameters(node);
matchToken(tokEOL);
return node;
}
TreeNode* Parser::FontSize()
{
TreeNode* node = new TreeNode(currentToken, FontSizeNode);
preservedToken = currentToken;
getToken();
appendParameters(node);
matchToken(tokEOL);
return node;
}
TreeNode* Parser::Wait()
{
TreeNode* node = new TreeNode(currentToken, WaitNode);
preservedToken = currentToken;
getToken();
appendParameters(node);
matchToken(tokEOL);
return node;
}
TreeNode* Parser::ExternalRun()
{
TreeNode* node = new TreeNode(currentToken, runNode);
preservedToken = currentToken;
getToken();
node->appendChild( Expression() );
// matchToken(tokEOL); this command can return values so can be used as expression/parameter
return node;
}
// Functions that take 2 arguments
TreeNode* Parser::Go()
{
TreeNode* node = new TreeNode(currentToken, GoNode);
preservedToken = currentToken;
getToken();
appendParameters(node);
matchToken(tokEOL);
return node;
}
TreeNode* Parser::ResizeCanvas()
{
TreeNode* node = new TreeNode(currentToken, ResizeCanvasNode);
preservedToken = currentToken;
getToken();
appendParameters(node);
matchToken(tokEOL);
return node;
}
TreeNode* Parser::Random()
{
TreeNode* node = new TreeNode(currentToken, RandomNode);
preservedToken = currentToken;
getToken();
appendParameters(node);
// matchToken(tokEOL); this command can return values so can be used as expression/parameter
return node;
}
// Functions that take 3 arguments
TreeNode* Parser::SetFgColor()
{
TreeNode* node = new TreeNode(currentToken, SetFgColorNode);
preservedToken = currentToken;
getToken();
appendParameters(node);
matchToken(tokEOL);
return node;
}
TreeNode* Parser::SetBgColor()
{
TreeNode* node = new TreeNode(currentToken, SetBgColorNode);
preservedToken = currentToken;
getToken();
appendParameters(node);
matchToken(tokEOL);
return node;
}
// Weirdo's (learn, execution controllers, print, and Other()s)
TreeNode* Parser::Learn()
{
preservedToken = currentToken;
matchToken(tokLearn); // skip the 'dummy' command
TreeNode* func = new TreeNode(currentToken, functionNode);
getToken(); // get the token after the function's name
TreeNode* idList = new TreeNode(currentToken, idListNode, "idlist");
if (currentToken.type != tokBegin)
{
if (currentToken.type == tokUnknown) idList->appendChild( getId() );
else
{
Error(currentToken, "Expected a parameter name or a '[' after the learn command.", 3030);
getToken(); // this recovers from the error
}
while (currentToken.type == tokComma)
{
matchToken(tokComma);
idList->appendChild( getId() );
}
}
func->appendChild(idList);
learnedFunctionList.append( func->getLook() ); // publish the function
func->appendChild( Block() );
return func;
}
TreeNode* Parser::If()
{
TreeNode* node = new TreeNode(currentToken, ifNode);
preservedToken = currentToken;
matchToken(tokIf);
node->appendChild( Expression() );
if (currentToken.type == tokDo) getToken(); // skip dummy word 'do'
if (currentToken.type == tokBegin) node->appendChild( Block() ); // if followed by a block
else node->appendChild( Statement() ); // if followed by single statement
while (currentToken.type == tokEOL) getToken(); // allow the else keyword to be on later lines
if (currentToken.type == tokElse) // else part
{
matchToken(tokElse);
while (currentToken.type == tokEOL) getToken();
if (currentToken.type == tokDo) getToken(); // next word
if(currentToken.type == tokBegin) node->appendChild( Block() ); // else is followed by block
else node->appendChild( Statement() );
}
return node;
}
TreeNode* Parser::While()
{
TreeNode* node = new TreeNode(currentToken, whileNode);
preservedToken = currentToken;
matchToken(tokWhile);
node->appendChild( Expression() );
node->appendChild( Block() );
return node;
}
TreeNode* Parser::For()
{
TreeNode* fNode = new TreeNode(currentToken, forNode);
preservedToken = currentToken;
matchToken(tokFor);
fNode->appendChild( getId() ); // loop id
matchToken(tokAssign);
fNode->appendChild( Expression() ); // start value expression
matchToken(tokTo);
fNode->appendChild( Expression() ); // stop value expression
if (currentToken.type == tokStep)
{
matchToken(tokStep);
fNode->appendChild( Expression() ); //step expression
}
while (currentToken.type == tokEOL) getToken(); // newlines are allowed
if (currentToken.type == tokBegin) fNode->appendChild( Block() ); // for followed by a block
else fNode->appendChild( Statement() ); // while followed by single statement
return fNode;
}
TreeNode* Parser::Repeat()
{
TreeNode* node = new TreeNode(currentToken, RepeatNode);
preservedToken = currentToken; // preserve token, else Match() will make sure it gets lost
matchToken(tokRepeat);
node->appendChild( Expression() );
node->appendChild( Block() );
return node;
}
TreeNode* Parser::ForEach()
{
TreeNode* fNode = new TreeNode(currentToken, forEachNode);
preservedToken = currentToken;
matchToken(tokForEach);
fNode->appendChild( Expression() );
matchToken(tokIn);
fNode->appendChild( Expression() );
if (currentToken.type == tokBegin) fNode->appendChild( Block() ); // for followed by a block
else fNode->appendChild( Statement() ); // while followed by single statement
return fNode;
}
TreeNode* Parser::Print()
{
TreeNode* node = new TreeNode(currentToken, printNode);
preservedToken = currentToken; // preserve token, else Match() will make sure it gets lost
getToken();
if (currentToken.type == tokEOL) return node; // print called without expressions
node->appendChild( Expression() ); // first expression
// following strings or expressions
while (currentToken.type == tokComma)
{
getToken(); // the comma
node->appendChild( Expression() );
}
matchToken(tokEOL);
return node;
}
TreeNode* Parser::Return()
{
TreeNode* ret = new TreeNode(currentToken, returnNode);
matchToken(tokReturn);
ret->appendChild( Expression() );
return ret;
}
TreeNode* Parser::Break()
{
TreeNode* brk = new TreeNode(currentToken, breakNode);
matchToken(tokBreak);
return brk;
}
TreeNode* Parser::EndOfFile()
{
TreeNode* node = new TreeNode(currentToken, EndOfFileNode);
return node;
}
TreeNode* Parser::Other()
{
// this is either an assignment or a function call!
kdDebug(0)<<"Parser::Other()"<<endl;
Token rememberedToken = currentToken; // preserve token, else Match() will make sure it gets lost
matchToken(tokUnknown);
if (currentToken.type == tokAssign) return Assignment(rememberedToken);
else if (learnedFunctionList.contains(rememberedToken.look) > 0)
{
TreeNode* node;
node = FunctionCall(rememberedToken);
// node->setType(funcReturnNode);
return node;
}
Error(rememberedToken, i18n("'%1' is neither a Logo command nor a learned command.").arg(rememberedToken.look), 1020);
TreeNode* errNode = new TreeNode(rememberedToken, Unknown);
// skip the rest of the line
while (currentToken.type != tokEOL) getToken();
return errNode;
}
void Parser::Error(Token& t, const TQString& s, uint code)
{
emit ErrorMsg(t, s, code);
}
#include "parser.moc"