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