implemented optional arguments

actorid
Marc Zinnschlag 15 years ago
parent 17135a6403
commit f4e79a48f0

@ -17,21 +17,21 @@ namespace Compiler
{ {
std::pair<Codes, Codes> entry; std::pair<Codes, Codes> entry;
if (mState!=IfElseBodyState) if (mState!=IfElseBodyState)
mExprParser.append (entry.first); mExprParser.append (entry.first);
std::copy (mCodeBlock.begin(), mCodeBlock.end(), std::copy (mCodeBlock.begin(), mCodeBlock.end(),
std::back_inserter (entry.second)); std::back_inserter (entry.second));
mIfCode.push_back (entry); mIfCode.push_back (entry);
mCodeBlock.clear(); mCodeBlock.clear();
if (keyword==Scanner::K_endif) if (keyword==Scanner::K_endif)
{ {
// store code for if-cascade // store code for if-cascade
Codes codes; Codes codes;
for (IfCodes::reverse_iterator iter (mIfCode.rbegin()); for (IfCodes::reverse_iterator iter (mIfCode.rbegin());
iter!=mIfCode.rend(); ++iter) iter!=mIfCode.rend(); ++iter)
{ {
@ -47,17 +47,17 @@ namespace Compiler
std::back_inserter (block)); std::back_inserter (block));
Generator::jumpOnZero (block, iter->second.size()+1); Generator::jumpOnZero (block, iter->second.size()+1);
} }
std::copy (iter->second.begin(), iter->second.end(), std::copy (iter->second.begin(), iter->second.end(),
std::back_inserter (block)); std::back_inserter (block));
std::swap (codes, block); std::swap (codes, block);
std::copy (block.begin(), block.end(), std::back_inserter (codes)); std::copy (block.begin(), block.end(), std::back_inserter (codes));
} }
std::copy (codes.begin(), codes.end(), std::back_inserter (mCode)); std::copy (codes.begin(), codes.end(), std::back_inserter (mCode));
mIfCode.clear(); mIfCode.clear();
mState = IfEndifState; mState = IfEndifState;
} }
@ -66,36 +66,36 @@ namespace Compiler
mExprParser.reset(); mExprParser.reset();
scanner.scan (mExprParser); scanner.scan (mExprParser);
mState = IfElseifEndState; mState = IfElseifEndState;
} }
else if (keyword==Scanner::K_else) else if (keyword==Scanner::K_else)
{ {
mState = IfElseEndState; mState = IfElseEndState;
} }
return true; return true;
} }
else if (keyword==Scanner::K_if || keyword==Scanner::K_while) else if (keyword==Scanner::K_if || keyword==Scanner::K_while)
{ {
// nested // nested
ControlParser parser (getErrorHandler(), getContext(), mLocals, mLiterals); ControlParser parser (getErrorHandler(), getContext(), mLocals, mLiterals);
if (parser.parseKeyword (keyword, loc, scanner)) if (parser.parseKeyword (keyword, loc, scanner))
scanner.scan (parser); scanner.scan (parser);
parser.appendCode (mCodeBlock); parser.appendCode (mCodeBlock);
return true; return true;
} }
else else
{ {
mLineParser.reset(); mLineParser.reset();
if (mLineParser.parseKeyword (keyword, loc, scanner)) if (mLineParser.parseKeyword (keyword, loc, scanner))
scanner.scan (mLineParser); scanner.scan (mLineParser);
return true; return true;
} }
return false; return false;
} }
@ -104,24 +104,24 @@ namespace Compiler
if (keyword==Scanner::K_endwhile) if (keyword==Scanner::K_endwhile)
{ {
Codes loop; Codes loop;
Codes expr; Codes expr;
mExprParser.append (expr); mExprParser.append (expr);
Generator::jump (loop, -mCodeBlock.size()-expr.size()); Generator::jump (loop, -mCodeBlock.size()-expr.size());
std::copy (expr.begin(), expr.end(), std::back_inserter (mCode)); std::copy (expr.begin(), expr.end(), std::back_inserter (mCode));
Codes skip; Codes skip;
Generator::jumpOnZero (skip, mCodeBlock.size()+loop.size()+1); Generator::jumpOnZero (skip, mCodeBlock.size()+loop.size()+1);
std::copy (skip.begin(), skip.end(), std::back_inserter (mCode)); std::copy (skip.begin(), skip.end(), std::back_inserter (mCode));
std::copy (mCodeBlock.begin(), mCodeBlock.end(), std::back_inserter (mCode)); std::copy (mCodeBlock.begin(), mCodeBlock.end(), std::back_inserter (mCode));
Codes loop2; Codes loop2;
Generator::jump (loop2, -mCodeBlock.size()-expr.size()-skip.size()); Generator::jump (loop2, -mCodeBlock.size()-expr.size()-skip.size());
if (loop.size()!=loop2.size()) if (loop.size()!=loop2.size())
@ -129,31 +129,31 @@ namespace Compiler
"internal compiler error: failed to generate a while loop"); "internal compiler error: failed to generate a while loop");
std::copy (loop2.begin(), loop2.end(), std::back_inserter (mCode)); std::copy (loop2.begin(), loop2.end(), std::back_inserter (mCode));
mState = WhileEndwhileState; mState = WhileEndwhileState;
return true; return true;
} }
else if (keyword==Scanner::K_if || keyword==Scanner::K_while) else if (keyword==Scanner::K_if || keyword==Scanner::K_while)
{ {
// nested // nested
ControlParser parser (getErrorHandler(), getContext(), mLocals, mLiterals); ControlParser parser (getErrorHandler(), getContext(), mLocals, mLiterals);
if (parser.parseKeyword (keyword, loc, scanner)) if (parser.parseKeyword (keyword, loc, scanner))
scanner.scan (parser); scanner.scan (parser);
parser.appendCode (mCodeBlock); parser.appendCode (mCodeBlock);
return true; return true;
} }
else else
{ {
mLineParser.reset(); mLineParser.reset();
if (mLineParser.parseKeyword (keyword, loc, scanner)) if (mLineParser.parseKeyword (keyword, loc, scanner))
scanner.scan (mLineParser); scanner.scan (mLineParser);
return true; return true;
} }
return false; return false;
} }
@ -164,14 +164,14 @@ namespace Compiler
mExprParser (errorHandler, context, locals, literals), mExprParser (errorHandler, context, locals, literals),
mState (StartState) mState (StartState)
{ {
} }
void ControlParser::appendCode (std::vector<Interpreter::Type_Code>& code) const void ControlParser::appendCode (std::vector<Interpreter::Type_Code>& code) const
{ {
std::copy (mCode.begin(), mCode.end(), std::back_inserter (code)); std::copy (mCode.begin(), mCode.end(), std::back_inserter (code));
} }
bool ControlParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) bool ControlParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner)
{ {
if (mState==StartState) if (mState==StartState)
@ -190,20 +190,20 @@ namespace Compiler
scanner.scan (mExprParser); scanner.scan (mExprParser);
mState = WhileEndState; mState = WhileEndState;
return true; return true;
} }
} }
else if (mState==IfBodyState || mState==IfElseifBodyState || mState==IfElseBodyState) else if (mState==IfBodyState || mState==IfElseifBodyState || mState==IfElseBodyState)
{ {
if (parseIfBody (keyword, loc, scanner)) if (parseIfBody (keyword, loc, scanner))
return true; return true;
} }
else if (mState==WhileBodyState) else if (mState==WhileBodyState)
{ {
if ( parseWhileBody (keyword, loc, scanner)) if ( parseWhileBody (keyword, loc, scanner))
return true; return true;
} }
return Parser::parseKeyword (keyword, loc, scanner); return Parser::parseKeyword (keyword, loc, scanner);
} }
@ -218,24 +218,24 @@ namespace Compiler
case IfElseEndState: mState = IfElseBodyState; return true; case IfElseEndState: mState = IfElseBodyState; return true;
case WhileEndState: mState = WhileBodyState; return true; case WhileEndState: mState = WhileBodyState; return true;
case IfBodyState: case IfBodyState:
case IfElseifBodyState: case IfElseifBodyState:
case IfElseBodyState: case IfElseBodyState:
case WhileBodyState: case WhileBodyState:
return true; // empty line return true; // empty line
case IfEndifState: case IfEndifState:
case WhileEndwhileState: case WhileEndwhileState:
return false; return false;
default: ; default: ;
} }
} }
return Parser::parseSpecial (code, loc, scanner); return Parser::parseSpecial (code, loc, scanner);
} }
@ -245,6 +245,6 @@ namespace Compiler
mCodeBlock.clear(); mCodeBlock.clear();
mIfCode.clear(); mIfCode.clear();
mState = StartState; mState = StartState;
Parser::reset();
} }
} }

@ -22,33 +22,33 @@ namespace Compiler
switch (op) switch (op)
{ {
case '(': case '(':
return 0; return 0;
case 'e': // == case 'e': // ==
case 'n': // != case 'n': // !=
case 'l': // < case 'l': // <
case 'L': // <= case 'L': // <=
case 'g': // < case 'g': // <
case 'G': // >= case 'G': // >=
return 1; return 1;
case '+': case '+':
case '-': case '-':
return 2; return 2;
case '*': case '*':
case '/': case '/':
return 3; return 3;
case 'm': case 'm':
return 4; return 4;
} }
return 0; return 0;
} }
@ -59,7 +59,7 @@ namespace Compiler
assert (Index<static_cast<int> (mOperands.size())); assert (Index<static_cast<int> (mOperands.size()));
return mOperands[mOperands.size()-1-Index]; return mOperands[mOperands.size()-1-Index];
} }
char ExprParser::getOperator() const char ExprParser::getOperator() const
{ {
assert (!mOperators.empty()); assert (!mOperators.empty());
@ -70,27 +70,27 @@ namespace Compiler
{ {
return std::find (mOperators.begin(), mOperators.end(), '(')!=mOperators.end(); return std::find (mOperators.begin(), mOperators.end(), '(')!=mOperators.end();
} }
void ExprParser::popOperator() void ExprParser::popOperator()
{ {
assert (!mOperators.empty()); assert (!mOperators.empty());
mOperators.resize (mOperators.size()-1); mOperators.resize (mOperators.size()-1);
} }
void ExprParser::popOperand() void ExprParser::popOperand()
{ {
assert (!mOperands.empty()); assert (!mOperands.empty());
mOperands.resize (mOperands.size()-1); mOperands.resize (mOperands.size()-1);
} }
void ExprParser::replaceBinaryOperands() void ExprParser::replaceBinaryOperands()
{ {
char t1 = getOperandType (1); char t1 = getOperandType (1);
char t2 = getOperandType(); char t2 = getOperandType();
popOperand(); popOperand();
popOperand(); popOperand();
if (t1==t2) if (t1==t2)
mOperands.push_back (t1); mOperands.push_back (t1);
else if (t1=='f' || t2=='f') else if (t1=='f' || t2=='f')
@ -102,59 +102,59 @@ namespace Compiler
void ExprParser::pop() void ExprParser::pop()
{ {
char op = getOperator(); char op = getOperator();
switch (op) switch (op)
{ {
case 'm': case 'm':
Generator::negate (mCode, getOperandType()); Generator::negate (mCode, getOperandType());
popOperator(); popOperator();
break; break;
case '+': case '+':
Generator::add (mCode, getOperandType (1), getOperandType()); Generator::add (mCode, getOperandType (1), getOperandType());
popOperator(); popOperator();
replaceBinaryOperands(); replaceBinaryOperands();
break; break;
case '-': case '-':
Generator::sub (mCode, getOperandType (1), getOperandType()); Generator::sub (mCode, getOperandType (1), getOperandType());
popOperator(); popOperator();
replaceBinaryOperands(); replaceBinaryOperands();
break; break;
case '*': case '*':
Generator::mul (mCode, getOperandType (1), getOperandType()); Generator::mul (mCode, getOperandType (1), getOperandType());
popOperator(); popOperator();
replaceBinaryOperands(); replaceBinaryOperands();
break; break;
case '/': case '/':
Generator::div (mCode, getOperandType (1), getOperandType()); Generator::div (mCode, getOperandType (1), getOperandType());
popOperator(); popOperator();
replaceBinaryOperands(); replaceBinaryOperands();
break; break;
case 'e': case 'e':
case 'n': case 'n':
case 'l': case 'l':
case 'L': case 'L':
case 'g': case 'g':
case 'G': case 'G':
Generator::compare (mCode, op, getOperandType (1), getOperandType()); Generator::compare (mCode, op, getOperandType (1), getOperandType());
popOperator(); popOperator();
popOperand(); popOperand();
popOperand(); popOperand();
mOperands.push_back ('l'); mOperands.push_back ('l');
break; break;
default: default:
throw std::logic_error ("unknown operator"); throw std::logic_error ("unknown operator");
} }
} }
@ -165,36 +165,36 @@ namespace Compiler
mOperands.push_back ('l'); mOperands.push_back ('l');
Generator::pushInt (mCode, mLiterals, value); Generator::pushInt (mCode, mLiterals, value);
} }
void ExprParser::pushFloatLiteral (float value) void ExprParser::pushFloatLiteral (float value)
{ {
mNextOperand = false; mNextOperand = false;
mOperands.push_back ('f'); mOperands.push_back ('f');
Generator::pushFloat (mCode, mLiterals, value); Generator::pushFloat (mCode, mLiterals, value);
} }
void ExprParser::pushBinaryOperator (char c) void ExprParser::pushBinaryOperator (char c)
{ {
while (!mOperators.empty() && getPriority (getOperator())>=getPriority (c)) while (!mOperators.empty() && getPriority (getOperator())>=getPriority (c))
pop(); pop();
mOperators.push_back (c); mOperators.push_back (c);
mNextOperand = true; mNextOperand = true;
} }
void ExprParser::close() void ExprParser::close()
{ {
while (getOperator()!='(') while (getOperator()!='(')
pop(); pop();
popOperator(); popOperator();
} }
void ExprParser::parseArguments (const std::string& arguments, Scanner& scanner) int ExprParser::parseArguments (const std::string& arguments, Scanner& scanner)
{ {
parseArguments (arguments, scanner, mCode); return parseArguments (arguments, scanner, mCode);
} }
ExprParser::ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals, ExprParser::ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
Literals& literals, bool argument) Literals& literals, bool argument)
: Parser (errorHandler, context), mLocals (locals), mLiterals (literals), : Parser (errorHandler, context), mLocals (locals), mLiterals (literals),
@ -205,11 +205,13 @@ namespace Compiler
{ {
if (!mExplicit.empty()) if (!mExplicit.empty())
return Parser::parseInt (value, loc, scanner); return Parser::parseInt (value, loc, scanner);
mFirst = false; mFirst = false;
if (mNextOperand) if (mNextOperand)
{ {
start();
pushIntegerLiteral (value); pushIntegerLiteral (value);
mTokenLoc = loc; mTokenLoc = loc;
return true; return true;
@ -228,13 +230,15 @@ namespace Compiler
return Parser::parseFloat (value, loc, scanner); return Parser::parseFloat (value, loc, scanner);
mFirst = false; mFirst = false;
if (mNextOperand) if (mNextOperand)
{ {
start();
pushFloatLiteral (value); pushFloatLiteral (value);
mTokenLoc = loc; mTokenLoc = loc;
return true; return true;
} }
else else
{ {
// no comma was used between arguments // no comma was used between arguments
@ -252,29 +256,31 @@ namespace Compiler
mFirst = false; mFirst = false;
if (mNextOperand) if (mNextOperand)
{ {
start();
std::string name2 = toLower (name); std::string name2 = toLower (name);
char type = mLocals.getType (name2); char type = mLocals.getType (name2);
if (type!=' ') if (type!=' ')
{ {
Generator::fetchLocal (mCode, type, mLocals.getIndex (name2)); Generator::fetchLocal (mCode, type, mLocals.getIndex (name2));
mNextOperand = false; mNextOperand = false;
mOperands.push_back (type=='f' ? 'f' : 'l'); mOperands.push_back (type=='f' ? 'f' : 'l');
return true; return true;
} }
type = getContext().getGlobalType (name2); type = getContext().getGlobalType (name2);
if (type!=' ') if (type!=' ')
{ {
Generator::fetchGlobal (mCode, mLiterals, type, name2); Generator::fetchGlobal (mCode, mLiterals, type, name2);
mNextOperand = false; mNextOperand = false;
mOperands.push_back (type=='f' ? 'f' : 'l'); mOperands.push_back (type=='f' ? 'f' : 'l');
return true; return true;
} }
if (mExplicit.empty() && getContext().isId (name)) if (mExplicit.empty() && getContext().isId (name))
{ {
mExplicit = name; mExplicit = name;
@ -287,161 +293,183 @@ namespace Compiler
scanner.putbackName (name, loc); scanner.putbackName (name, loc);
return false; return false;
} }
return Parser::parseName (name, loc, scanner); return Parser::parseName (name, loc, scanner);
} }
bool ExprParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) bool ExprParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner)
{ {
mFirst = false; mFirst = false;
if (!mExplicit.empty()) if (!mExplicit.empty())
{ {
if (mRefOp && mNextOperand) if (mRefOp && mNextOperand)
{ {
if (keyword==Scanner::K_getdisabled) if (keyword==Scanner::K_getdisabled)
{ {
mTokenLoc = loc; start();
mTokenLoc = loc;
Generator::getDisabled (mCode, mLiterals, mExplicit); Generator::getDisabled (mCode, mLiterals, mExplicit);
mOperands.push_back ('l'); mOperands.push_back ('l');
mExplicit.clear(); mExplicit.clear();
mRefOp = false; mRefOp = false;
mNextOperand = false; mNextOperand = false;
return true; return true;
} }
else if (keyword==Scanner::K_getdistance) else if (keyword==Scanner::K_getdistance)
{ {
start();
mTokenLoc = loc; mTokenLoc = loc;
parseArguments ("c", scanner); parseArguments ("c", scanner);
Generator::getDistance (mCode, mLiterals, mExplicit); Generator::getDistance (mCode, mLiterals, mExplicit);
mOperands.push_back ('f'); mOperands.push_back ('f');
mExplicit.clear(); mExplicit.clear();
mRefOp = false; mRefOp = false;
mNextOperand = false; mNextOperand = false;
return true; return true;
} }
// check for custom extensions // check for custom extensions
if (const Extensions *extensions = getContext().getExtensions()) if (const Extensions *extensions = getContext().getExtensions())
{ {
char returnType; char returnType;
std::string argumentType; std::string argumentType;
if (extensions->isFunction (keyword, returnType, argumentType, true)) if (extensions->isFunction (keyword, returnType, argumentType, true))
{ {
start();
mTokenLoc = loc; mTokenLoc = loc;
parseArguments (argumentType, scanner); parseArguments (argumentType, scanner);
extensions->generateFunctionCode (keyword, mCode, mLiterals, mExplicit); extensions->generateFunctionCode (keyword, mCode, mLiterals, mExplicit);
mOperands.push_back (returnType); mOperands.push_back (returnType);
mExplicit.clear(); mExplicit.clear();
mRefOp = false; mRefOp = false;
mNextOperand = false; mNextOperand = false;
return true; return true;
} }
} }
} }
return Parser::parseKeyword (keyword, loc, scanner); return Parser::parseKeyword (keyword, loc, scanner);
} }
if (mNextOperand) if (mNextOperand)
{ {
if (keyword==Scanner::K_getsquareroot) if (keyword==Scanner::K_getsquareroot)
{ {
mTokenLoc = loc; start();
mTokenLoc = loc;
parseArguments ("f", scanner); parseArguments ("f", scanner);
Generator::squareRoot (mCode); Generator::squareRoot (mCode);
mOperands.push_back ('f'); mOperands.push_back ('f');
mNextOperand = false; mNextOperand = false;
return true; return true;
} }
else if (keyword==Scanner::K_menumode) else if (keyword==Scanner::K_menumode)
{ {
start();
mTokenLoc = loc; mTokenLoc = loc;
Generator::menuMode (mCode); Generator::menuMode (mCode);
mOperands.push_back ('l'); mOperands.push_back ('l');
mNextOperand = false; mNextOperand = false;
return true; return true;
} }
else if (keyword==Scanner::K_random) else if (keyword==Scanner::K_random)
{ {
mTokenLoc = loc; start();
mTokenLoc = loc;
parseArguments ("l", scanner); parseArguments ("l", scanner);
Generator::random (mCode); Generator::random (mCode);
mOperands.push_back ('l'); mOperands.push_back ('l');
mNextOperand = false; mNextOperand = false;
return true; return true;
} }
else if (keyword==Scanner::K_scriptrunning) else if (keyword==Scanner::K_scriptrunning)
{ {
start();
mTokenLoc = loc; mTokenLoc = loc;
parseArguments ("c", scanner); parseArguments ("c", scanner);
Generator::scriptRunning (mCode); Generator::scriptRunning (mCode);
mOperands.push_back ('l'); mOperands.push_back ('l');
mNextOperand = false; mNextOperand = false;
return true; return true;
} }
else if (keyword==Scanner::K_getdistance) else if (keyword==Scanner::K_getdistance)
{ {
start();
mTokenLoc = loc; mTokenLoc = loc;
parseArguments ("c", scanner); parseArguments ("c", scanner);
Generator::getDistance (mCode, mLiterals, ""); Generator::getDistance (mCode, mLiterals, "");
mOperands.push_back ('f'); mOperands.push_back ('f');
mNextOperand = false; mNextOperand = false;
return true; return true;
} }
else if (keyword==Scanner::K_getsecondspassed) else if (keyword==Scanner::K_getsecondspassed)
{ {
mTokenLoc = loc; start();
mTokenLoc = loc;
Generator::getSecondsPassed (mCode); Generator::getSecondsPassed (mCode);
mOperands.push_back ('f'); mOperands.push_back ('f');
mNextOperand = false; mNextOperand = false;
return true; return true;
} }
else if (keyword==Scanner::K_getdisabled) else if (keyword==Scanner::K_getdisabled)
{ {
mTokenLoc = loc; start();
mTokenLoc = loc;
Generator::getDisabled (mCode, mLiterals, ""); Generator::getDisabled (mCode, mLiterals, "");
mOperands.push_back ('l'); mOperands.push_back ('l');
mNextOperand = false; mNextOperand = false;
return true; return true;
} }
else else
{ {
// check for custom extensions // check for custom extensions
if (const Extensions *extensions = getContext().getExtensions()) if (const Extensions *extensions = getContext().getExtensions())
{ {
start();
char returnType; char returnType;
std::string argumentType; std::string argumentType;
if (extensions->isFunction (keyword, returnType, argumentType, false)) if (extensions->isFunction (keyword, returnType, argumentType, false))
{ {
mTokenLoc = loc; mTokenLoc = loc;
parseArguments (argumentType, scanner); parseArguments (argumentType, scanner);
extensions->generateFunctionCode (keyword, mCode, mLiterals, ""); extensions->generateFunctionCode (keyword, mCode, mLiterals, "");
mOperands.push_back (returnType); mOperands.push_back (returnType);
mNextOperand = false; mNextOperand = false;
return true; return true;
} }
@ -454,7 +482,7 @@ namespace Compiler
scanner.putbackKeyword (keyword, loc); scanner.putbackKeyword (keyword, loc);
return false; return false;
} }
return Parser::parseKeyword (keyword, loc, scanner); return Parser::parseKeyword (keyword, loc, scanner);
} }
@ -467,10 +495,10 @@ namespace Compiler
mRefOp = true; mRefOp = true;
return true; return true;
} }
return Parser::parseSpecial (code, loc, scanner); return Parser::parseSpecial (code, loc, scanner);
} }
if (code==Scanner::S_comma) if (code==Scanner::S_comma)
{ {
mTokenLoc = loc; mTokenLoc = loc;
@ -481,14 +509,14 @@ namespace Compiler
mFirst = false; mFirst = false;
return true; return true;
} }
// end marker // end marker
scanner.putbackSpecial (code, loc); scanner.putbackSpecial (code, loc);
return false; return false;
} }
mFirst = false; mFirst = false;
if (code==Scanner::S_newline) if (code==Scanner::S_newline)
{ {
// end marker // end marker
@ -496,7 +524,7 @@ namespace Compiler
scanner.putbackSpecial (code, loc); scanner.putbackSpecial (code, loc);
return false; return false;
} }
if (code==Scanner::S_minus && mNextOperand) if (code==Scanner::S_minus && mNextOperand)
{ {
// unary // unary
@ -504,7 +532,7 @@ namespace Compiler
mTokenLoc = loc; mTokenLoc = loc;
return true; return true;
} }
if (code==Scanner::S_open) if (code==Scanner::S_open)
{ {
if (mNextOperand) if (mNextOperand)
@ -520,7 +548,7 @@ namespace Compiler
return false; return false;
} }
} }
if (code==Scanner::S_close && !mNextOperand) if (code==Scanner::S_close && !mNextOperand)
{ {
if (isOpen()) if (isOpen())
@ -528,17 +556,17 @@ namespace Compiler
close(); close();
return true; return true;
} }
mTokenLoc = loc; mTokenLoc = loc;
scanner.putbackSpecial (code, loc); scanner.putbackSpecial (code, loc);
return false; return false;
} }
if (!mNextOperand) if (!mNextOperand)
{ {
mTokenLoc = loc; mTokenLoc = loc;
char c = 0; // comparison char c = 0; // comparison
switch (code) switch (code)
{ {
case Scanner::S_plus: pushBinaryOperator ('+'); return true; case Scanner::S_plus: pushBinaryOperator ('+'); return true;
@ -552,7 +580,7 @@ namespace Compiler
case Scanner::S_cmpGT: c = 'g'; break; case Scanner::S_cmpGT: c = 'g'; break;
case Scanner::S_cmpGE: c = 'G'; break; case Scanner::S_cmpGE: c = 'G'; break;
} }
if (c) if (c)
{ {
if (mArgument && !isOpen()) if (mArgument && !isOpen())
@ -562,15 +590,15 @@ namespace Compiler
scanner.putbackSpecial (code, loc); scanner.putbackSpecial (code, loc);
return false; return false;
} }
pushBinaryOperator (c); pushBinaryOperator (c);
return true; return true;
} }
} }
return Parser::parseSpecial (code, loc, scanner); return Parser::parseSpecial (code, loc, scanner);
} }
void ExprParser::reset() void ExprParser::reset()
{ {
mOperands.clear(); mOperands.clear();
@ -580,8 +608,9 @@ namespace Compiler
mFirst = true; mFirst = true;
mExplicit.clear(); mExplicit.clear();
mRefOp = false; mRefOp = false;
Parser::reset();
} }
char ExprParser::append (std::vector<Interpreter::Type_Code>& code) char ExprParser::append (std::vector<Interpreter::Type_Code>& code)
{ {
if (mOperands.empty() && mOperators.empty()) if (mOperands.empty() && mOperators.empty())
@ -589,7 +618,7 @@ namespace Compiler
getErrorHandler().error ("missing expression", mTokenLoc); getErrorHandler().error ("missing expression", mTokenLoc);
return 'l'; return 'l';
} }
if (mNextOperand || mOperands.empty()) if (mNextOperand || mOperands.empty())
{ {
getErrorHandler().error ("syntax error in expression", mTokenLoc); getErrorHandler().error ("syntax error in expression", mTokenLoc);
@ -603,62 +632,90 @@ namespace Compiler
assert (mOperands.size()==1); assert (mOperands.size()==1);
return mOperands[0]; return mOperands[0];
} }
void ExprParser::parseArguments (const std::string& arguments, Scanner& scanner, int ExprParser::parseArguments (const std::string& arguments, Scanner& scanner,
std::vector<Interpreter::Type_Code>& code, bool invert) std::vector<Interpreter::Type_Code>& code, bool invert)
{ {
bool optional = false;
bool optionalCount = 0;
ExprParser parser (getErrorHandler(), getContext(), mLocals, mLiterals, true); ExprParser parser (getErrorHandler(), getContext(), mLocals, mLiterals, true);
StringParser stringParser (getErrorHandler(), getContext(), mLiterals); StringParser stringParser (getErrorHandler(), getContext(), mLiterals);
std::stack<std::vector<Interpreter::Type_Code> > stack; std::stack<std::vector<Interpreter::Type_Code> > stack;
for (std::string::const_iterator iter (arguments.begin()); iter!=arguments.end(); for (std::string::const_iterator iter (arguments.begin()); iter!=arguments.end();
++iter) ++iter)
{ {
if (*iter=='S' || *iter=='c') if (*iter=='/')
{
optional = true;
}
else if (*iter=='S' || *iter=='c')
{ {
stringParser.reset(); stringParser.reset();
if (optional)
stringParser.setOptional (true);
if (*iter=='c') stringParser.smashCase(); if (*iter=='c') stringParser.smashCase();
scanner.scan (stringParser); scanner.scan (stringParser);
if (optional && stringParser.isEmpty())
break;
if (invert) if (invert)
{ {
std::vector<Interpreter::Type_Code> tmp; std::vector<Interpreter::Type_Code> tmp;
stringParser.append (tmp); stringParser.append (tmp);
stack.push (tmp); stack.push (tmp);
} }
else else
stringParser.append (code); stringParser.append (code);
if (optional)
++optionalCount;
} }
else else
{ {
parser.reset(); parser.reset();
if (optional)
parser.setOptional (true);
scanner.scan (parser); scanner.scan (parser);
if (optional && parser.isEmpty())
break;
std::vector<Interpreter::Type_Code> tmp; std::vector<Interpreter::Type_Code> tmp;
char type = parser.append (tmp); char type = parser.append (tmp);
if (type!=*iter) if (type!=*iter)
Generator::convert (tmp, type, *iter); Generator::convert (tmp, type, *iter);
if (invert) if (invert)
stack.push (tmp); stack.push (tmp);
else else
std::copy (tmp.begin(), tmp.end(), std::back_inserter (code)); std::copy (tmp.begin(), tmp.end(), std::back_inserter (code));
if (optional)
++optionalCount;
} }
} }
while (!stack.empty()) while (!stack.empty())
{ {
std::vector<Interpreter::Type_Code>& tmp = stack.top(); std::vector<Interpreter::Type_Code>& tmp = stack.top();
std::copy (tmp.begin(), tmp.end(), std::back_inserter (code)); std::copy (tmp.begin(), tmp.end(), std::back_inserter (code));
stack.pop(); stack.pop();
} }
}
}
return optionalCount;
}
}

@ -15,7 +15,7 @@ namespace Compiler
class ExprParser : public Parser class ExprParser : public Parser
{ {
Locals& mLocals; Locals& mLocals;
Literals& mLiterals; Literals& mLiterals;
std::vector<char> mOperands; std::vector<char> mOperands;
std::vector<char> mOperators; std::vector<char> mOperators;
@ -26,35 +26,35 @@ namespace Compiler
bool mArgument; bool mArgument;
std::string mExplicit; std::string mExplicit;
bool mRefOp; bool mRefOp;
int getPriority (char op) const; int getPriority (char op) const;
char getOperandType (int Index = 0) const; char getOperandType (int Index = 0) const;
char getOperator() const; char getOperator() const;
bool isOpen() const; bool isOpen() const;
void popOperator(); void popOperator();
void popOperand(); void popOperand();
void replaceBinaryOperands(); void replaceBinaryOperands();
void pop(); void pop();
void pushIntegerLiteral (int value); void pushIntegerLiteral (int value);
void pushFloatLiteral (float value); void pushFloatLiteral (float value);
void pushBinaryOperator (char c); void pushBinaryOperator (char c);
void close(); void close();
void parseArguments (const std::string& arguments, Scanner& scanner); int parseArguments (const std::string& arguments, Scanner& scanner);
public: public:
ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals, ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
Literals& literals, bool argument = false); Literals& literals, bool argument = false);
///< constructor ///< constructor
@ -84,20 +84,22 @@ namespace Compiler
virtual bool parseSpecial (int code, const TokenLoc& loc, Scanner& scanner); virtual bool parseSpecial (int code, const TokenLoc& loc, Scanner& scanner);
///< Handle a special character token. ///< Handle a special character token.
/// \return fetch another token? /// \return fetch another token?
void reset(); void reset();
///< Reset parser to clean state. ///< Reset parser to clean state.
char append (std::vector<Interpreter::Type_Code>& code); char append (std::vector<Interpreter::Type_Code>& code);
///< Generate code for parsed expression. ///< Generate code for parsed expression.
/// \return Type ('l': integer, 'f': float) /// \return Type ('l': integer, 'f': float)
void parseArguments (const std::string& arguments, Scanner& scanner, int parseArguments (const std::string& arguments, Scanner& scanner,
std::vector<Interpreter::Type_Code>& code, bool invert = false); std::vector<Interpreter::Type_Code>& code, bool invert = false);
///< Parse sequence of arguments specified by \a arguments. ///< Parse sequence of arguments specified by \a arguments.
/// \param arguments Each character represents one arguments ('l': integer, /// \param arguments Each character represents one arguments ('l': integer,
/// 'f': float, 'S': string, 'c': string (case smashed)) /// 'f': float, 'S': string, 'c': string (case smashed), '/': following arguments are
/// optional)
/// \param invert Store arguments in reverted order. /// \param invert Store arguments in reverted order.
/// \return number of optional arguments
}; };
} }

@ -8,7 +8,7 @@
namespace Compiler namespace Compiler
{ {
FileParser::FileParser (ErrorHandler& errorHandler, Context& context) FileParser::FileParser (ErrorHandler& errorHandler, Context& context)
: Parser (errorHandler, context), : Parser (errorHandler, context),
mScriptParser (errorHandler, context, mLocals, true), mScriptParser (errorHandler, context, mLocals, true),
mState (BeginState) mState (BeginState)
{} {}
@ -17,12 +17,12 @@ namespace Compiler
{ {
return mName; return mName;
} }
void FileParser::getCode (std::vector<Interpreter::Type_Code>& code) const void FileParser::getCode (std::vector<Interpreter::Type_Code>& code) const
{ {
mScriptParser.getCode (code); mScriptParser.getCode (code);
} }
const Locals& FileParser::getLocals() const const Locals& FileParser::getLocals() const
{ {
return mLocals; return mLocals;
@ -37,17 +37,17 @@ namespace Compiler
mState = BeginCompleteState; mState = BeginCompleteState;
return true; return true;
} }
if (mState==EndNameState) if (mState==EndNameState)
{ {
// optional repeated name after end statement // optional repeated name after end statement
if (mName!=name) if (mName!=name)
reportWarning ("Names for script " + mName + " do not match", loc); reportWarning ("Names for script " + mName + " do not match", loc);
mState = EndCompleteState; mState = EndCompleteState;
return true; return true;
} }
return Parser::parseName (name, loc, scanner); return Parser::parseName (name, loc, scanner);
} }
@ -58,7 +58,7 @@ namespace Compiler
mState = NameState; mState = NameState;
return true; return true;
} }
if (mState==NameState) if (mState==NameState)
{ {
// keywords can be used as script names too. Thank you Morrowind for another // keywords can be used as script names too. Thank you Morrowind for another
@ -67,7 +67,7 @@ namespace Compiler
mState = BeginCompleteState; mState = BeginCompleteState;
return true; return true;
} }
return Parser::parseKeyword (keyword, loc, scanner); return Parser::parseKeyword (keyword, loc, scanner);
} }
@ -80,25 +80,25 @@ namespace Compiler
// ignore empty lines // ignore empty lines
return true; return true;
} }
if (mState==BeginCompleteState) if (mState==BeginCompleteState)
{ {
// parse the script body // parse the script body
mScriptParser.reset(); mScriptParser.reset();
scanner.scan (mScriptParser); scanner.scan (mScriptParser);
mState = EndNameState; mState = EndNameState;
return true; return true;
} }
if (mState==EndCompleteState || mState==EndNameState) if (mState==EndCompleteState || mState==EndNameState)
{ {
// we are done here -> ignore the rest of the script // we are done here -> ignore the rest of the script
return false; return false;
} }
} }
return Parser::parseSpecial (code, loc, scanner); return Parser::parseSpecial (code, loc, scanner);
} }
@ -107,12 +107,12 @@ namespace Compiler
if (mState!=EndNameState && mState!=EndCompleteState) if (mState!=EndNameState && mState!=EndCompleteState)
Parser::parseEOF (scanner); Parser::parseEOF (scanner);
} }
void FileParser::reset() void FileParser::reset()
{ {
mState = BeginState; mState = BeginState;
mName.clear(); mName.clear();
mScriptParser.reset(); mScriptParser.reset();
Parser::reset();
} }
} }

@ -57,15 +57,15 @@ namespace Compiler
std::string Parser::toLower (const std::string& name) std::string Parser::toLower (const std::string& name)
{ {
std::string lowerCase; std::string lowerCase;
std::transform (name.begin(), name.end(), std::back_inserter (lowerCase), std::transform (name.begin(), name.end(), std::back_inserter (lowerCase),
(int(*)(int)) std::tolower); (int(*)(int)) std::tolower);
return lowerCase; return lowerCase;
} }
Parser::Parser (ErrorHandler& errorHandler, Context& context) Parser::Parser (ErrorHandler& errorHandler, Context& context)
: mErrorHandler (errorHandler), mContext (context) : mErrorHandler (errorHandler), mContext (context), mOptional (false), mEmpty (true)
{} {}
// destructor // destructor
@ -79,7 +79,9 @@ namespace Compiler
bool Parser::parseInt (int value, const TokenLoc& loc, Scanner& scanner) bool Parser::parseInt (int value, const TokenLoc& loc, Scanner& scanner)
{ {
reportSeriousError ("Unexpected numeric value", loc); if (!(mOptional && mEmpty))
reportSeriousError ("Unexpected numeric value", loc);
return false; return false;
} }
@ -90,7 +92,9 @@ namespace Compiler
bool Parser::parseFloat (float value, const TokenLoc& loc, Scanner& scanner) bool Parser::parseFloat (float value, const TokenLoc& loc, Scanner& scanner)
{ {
reportSeriousError ("Unexpected floating point value", loc); if (!(mOptional && mEmpty))
reportSeriousError ("Unexpected floating point value", loc);
return false; return false;
} }
@ -102,7 +106,9 @@ namespace Compiler
bool Parser::parseName (const std::string& name, const TokenLoc& loc, bool Parser::parseName (const std::string& name, const TokenLoc& loc,
Scanner& scanner) Scanner& scanner)
{ {
reportSeriousError ("Unexpected name", loc); if (!(mOptional && mEmpty))
reportSeriousError ("Unexpected name", loc);
return false; return false;
} }
@ -113,7 +119,9 @@ namespace Compiler
bool Parser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) bool Parser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner)
{ {
reportSeriousError ("Unexpected keyword", loc); if (!(mOptional && mEmpty))
reportSeriousError ("Unexpected keyword", loc);
return false; return false;
} }
@ -124,7 +132,9 @@ namespace Compiler
bool Parser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner) bool Parser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner)
{ {
reportSeriousError ("Unexpected special token", loc); if (!(mOptional && mEmpty))
reportSeriousError ("Unexpected special token", loc);
return false; return false;
} }
@ -136,5 +146,25 @@ namespace Compiler
{ {
reportEOF(); reportEOF();
} }
}
void Parser::reset()
{
mOptional = false;
mEmpty = true;
}
void Parser::setOptional (bool optional)
{
mOptional = optional;
}
void Parser::start()
{
mEmpty = false;
}
bool Parser::isEmpty() const
{
return mEmpty;
}
}

@ -18,6 +18,8 @@ namespace Compiler
{ {
ErrorHandler& mErrorHandler; ErrorHandler& mErrorHandler;
Context& mContext; Context& mContext;
bool mOptional;
bool mEmpty;
protected: protected:
@ -47,7 +49,7 @@ namespace Compiler
///< constructor ///< constructor
virtual ~Parser(); virtual ~Parser();
///< destructor ///< destructor
virtual bool parseInt (int value, const TokenLoc& loc, Scanner& scanner); virtual bool parseInt (int value, const TokenLoc& loc, Scanner& scanner);
///< Handle an int token. ///< Handle an int token.
@ -84,6 +86,19 @@ namespace Compiler
///< Handle EOF token. ///< Handle EOF token.
/// ///
/// - Default-implementation: Report an error. /// - Default-implementation: Report an error.
virtual void reset();
///< Reset parser to clean state.
void setOptional (bool optional);
///< Optional mode: If nothign has been parsed yet and an unexpected token is delivered, stop
/// parsing without raising an exception (after a reset the parser is in non-optional mode).
void start();
///< Mark parser as non-empty (at least one token has been parser).
bool isEmpty() const;
///< Has anything been parsed?
}; };
} }

@ -12,7 +12,7 @@ namespace Compiler
StringParser::StringParser (ErrorHandler& errorHandler, Context& context, Literals& literals) StringParser::StringParser (ErrorHandler& errorHandler, Context& context, Literals& literals)
: Parser (errorHandler, context), mLiterals (literals), mState (StartState), mSmashCase (false) : Parser (errorHandler, context), mLiterals (literals), mState (StartState), mSmashCase (false)
{ {
} }
bool StringParser::parseName (const std::string& name, const TokenLoc& loc, bool StringParser::parseName (const std::string& name, const TokenLoc& loc,
@ -20,14 +20,15 @@ namespace Compiler
{ {
if (mState==StartState || mState==CommaState) if (mState==StartState || mState==CommaState)
{ {
start();
if (mSmashCase) if (mSmashCase)
Generator::pushString (mCode, mLiterals, toLower (name)); Generator::pushString (mCode, mLiterals, toLower (name));
else else
Generator::pushString (mCode, mLiterals, name); Generator::pushString (mCode, mLiterals, name);
return false; return false;
} }
return Parser::parseName (name, loc, scanner); return Parser::parseName (name, loc, scanner);
} }
@ -38,10 +39,10 @@ namespace Compiler
mState = CommaState; mState = CommaState;
return true; return true;
} }
return Parser::parseSpecial (code, loc, scanner); return Parser::parseSpecial (code, loc, scanner);
} }
void StringParser::append (std::vector<Interpreter::Type_Code>& code) void StringParser::append (std::vector<Interpreter::Type_Code>& code)
{ {
std::copy (mCode.begin(), mCode.end(), std::back_inserter (code)); std::copy (mCode.begin(), mCode.end(), std::back_inserter (code));
@ -52,11 +53,11 @@ namespace Compiler
mState = StartState; mState = StartState;
mCode.clear(); mCode.clear();
mSmashCase = false; mSmashCase = false;
Parser::reset();
} }
void StringParser::smashCase() void StringParser::smashCase()
{ {
mSmashCase = true; mSmashCase = true;
} }
} }

Loading…
Cancel
Save