Added class ParsePoint for keeping a context while parsing code.
Changed the Javascript parser to use this object. This patch fixes issues with incorrect parsing of imbricated if... else/if {} else {} or any of the combinations including a if else construct. git-svn-id: http://voip.null.ro/svn/yate@5464 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
parent
089242bfc5
commit
62835337f7
|
@ -143,6 +143,17 @@ bool ExpExtender::runAssign(ObjList& stack, const ExpOperation& oper, GenObject*
|
|||
return false;
|
||||
}
|
||||
|
||||
ParsePoint& ParsePoint::operator=(ParsePoint& parsePoint)
|
||||
{
|
||||
m_expr = parsePoint.m_expr;
|
||||
m_count = parsePoint.m_count;
|
||||
m_searchedSeps = parsePoint.m_searchedSeps;
|
||||
m_fileName = parsePoint.m_fileName;
|
||||
m_lineNo = parsePoint.m_lineNo;
|
||||
if (m_eval)
|
||||
m_eval->m_lineNo = m_lineNo;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ExpEvaluator::ExpEvaluator(const TokenDict* operators, const TokenDict* unaryOps)
|
||||
: m_operators(operators), m_unaryOps(unaryOps),
|
||||
|
@ -199,9 +210,9 @@ void ExpEvaluator::extender(ExpExtender* ext)
|
|||
TelEngine::destruct(tmp->refObj());
|
||||
}
|
||||
|
||||
char ExpEvaluator::skipWhites(const char*& expr)
|
||||
char ExpEvaluator::skipWhites(ParsePoint& expr)
|
||||
{
|
||||
if (!expr)
|
||||
if (!expr.m_expr)
|
||||
return 0;
|
||||
for (; ; expr++) {
|
||||
char c = *expr;
|
||||
|
@ -210,12 +221,12 @@ char ExpEvaluator::skipWhites(const char*& expr)
|
|||
case '\t':
|
||||
continue;
|
||||
case '\r':
|
||||
m_lineNo++;
|
||||
expr.m_lineNo = ++m_lineNo;
|
||||
if (expr[1] == '\n')
|
||||
expr++;
|
||||
continue;
|
||||
case '\n':
|
||||
m_lineNo++;
|
||||
expr.m_lineNo = ++m_lineNo;
|
||||
if (expr[1] == '\r')
|
||||
expr++;
|
||||
continue;
|
||||
|
@ -231,12 +242,12 @@ bool ExpEvaluator::keywordChar(char c) const
|
|||
('0' <= c && c <= '9') || (c == '_');
|
||||
}
|
||||
|
||||
char ExpEvaluator::skipComments(const char*& expr, GenObject* context)
|
||||
char ExpEvaluator::skipComments(ParsePoint& expr, GenObject* context)
|
||||
{
|
||||
return skipWhites(expr);
|
||||
}
|
||||
|
||||
int ExpEvaluator::preProcess(const char*& expr, GenObject* context)
|
||||
int ExpEvaluator::preProcess(ParsePoint& expr, GenObject* context)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
@ -290,16 +301,16 @@ void ExpEvaluator::formatLineNo(String& buf, unsigned int line) const
|
|||
buf << "line " << line;
|
||||
}
|
||||
|
||||
bool ExpEvaluator::getInstruction(const char*& expr, char stop, GenObject* nested)
|
||||
bool ExpEvaluator::getInstruction(ParsePoint& expr, char stop, GenObject* nested)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ExpEvaluator::getOperand(const char*& expr, bool endOk, int precedence)
|
||||
bool ExpEvaluator::getOperand(ParsePoint& expr, bool endOk, int precedence)
|
||||
{
|
||||
if (inError())
|
||||
return false;
|
||||
XDebug(this,DebugAll,"getOperand '%.30s'",expr);
|
||||
XDebug(this,DebugAll,"getOperand '%.30s'",(const char*)expr);
|
||||
if (!getOperandInternal(expr, endOk, precedence))
|
||||
return false;
|
||||
Opcode oper;
|
||||
|
@ -308,7 +319,7 @@ bool ExpEvaluator::getOperand(const char*& expr, bool endOk, int precedence)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ExpEvaluator::getOperandInternal(const char*& expr, bool endOk, int precedence)
|
||||
bool ExpEvaluator::getOperandInternal(ParsePoint& expr, bool endOk, int precedence)
|
||||
{
|
||||
char c = skipComments(expr);
|
||||
if (!c)
|
||||
|
@ -335,16 +346,16 @@ bool ExpEvaluator::getOperandInternal(const char*& expr, bool endOk, int precede
|
|||
return gotError("Expecting operand",expr);
|
||||
}
|
||||
|
||||
bool ExpEvaluator::getSimple(const char*& expr, bool constOnly)
|
||||
bool ExpEvaluator::getSimple(ParsePoint& expr, bool constOnly)
|
||||
{
|
||||
return getString(expr) || getNumber(expr);
|
||||
}
|
||||
|
||||
bool ExpEvaluator::getNumber(const char*& expr)
|
||||
bool ExpEvaluator::getNumber(ParsePoint& expr)
|
||||
{
|
||||
if (inError())
|
||||
return false;
|
||||
XDebug(this,DebugAll,"getNumber '%.30s'",expr);
|
||||
XDebug(this,DebugAll,"getNumber '%.30s'",(const char*)expr);
|
||||
char* endp = 0;
|
||||
long int val = ::strtol(expr,&endp,0);
|
||||
if (!endp || (endp == expr))
|
||||
|
@ -355,11 +366,11 @@ bool ExpEvaluator::getNumber(const char*& expr)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ExpEvaluator::getString(const char*& expr)
|
||||
bool ExpEvaluator::getString(ParsePoint& expr)
|
||||
{
|
||||
if (inError())
|
||||
return false;
|
||||
XDebug(this,DebugAll,"getString '%.30s'",expr);
|
||||
XDebug(this,DebugAll,"getString '%.30s'",(const char*)expr);
|
||||
char c = skipComments(expr);
|
||||
if (c == '"' || c == '\'') {
|
||||
String str;
|
||||
|
@ -434,18 +445,18 @@ int ExpEvaluator::getKeyword(const char* str) const
|
|||
return len;
|
||||
}
|
||||
|
||||
bool ExpEvaluator::getFunction(const char*& expr)
|
||||
bool ExpEvaluator::getFunction(ParsePoint& expr)
|
||||
{
|
||||
if (inError())
|
||||
return false;
|
||||
XDebug(this,DebugAll,"getFunction '%.30s'",expr);
|
||||
XDebug(this,DebugAll,"getFunction '%.30s'",(const char*)expr);
|
||||
skipComments(expr);
|
||||
int len = getKeyword(expr);
|
||||
const char* s = expr+len;
|
||||
unsigned int savedLine = m_lineNo;
|
||||
ParsePoint s = expr;
|
||||
s.m_expr = s.m_expr+len;
|
||||
skipComments(expr);
|
||||
if ((len <= 0) || (skipComments(s) != '(')) {
|
||||
m_lineNo = savedLine;
|
||||
expr.m_lineNo = s.m_lineNo;
|
||||
return false;
|
||||
}
|
||||
s++;
|
||||
|
@ -455,7 +466,7 @@ bool ExpEvaluator::getFunction(const char*& expr)
|
|||
if (!runCompile(s,')')) {
|
||||
if (!argc && (skipComments(s) == ')'))
|
||||
break;
|
||||
m_lineNo = savedLine;
|
||||
expr.m_lineNo = s.m_lineNo;
|
||||
return false;
|
||||
}
|
||||
argc++;
|
||||
|
@ -463,17 +474,17 @@ bool ExpEvaluator::getFunction(const char*& expr)
|
|||
if (skipComments(s) != ')')
|
||||
return gotError("Expecting ')' after function",s);
|
||||
String str(expr,len);
|
||||
expr = s+1;
|
||||
expr.m_expr = s.m_expr+1;
|
||||
DDebug(this,DebugAll,"Found %s()",str.safe());
|
||||
addOpcode(OpcFunc,str,argc);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ExpEvaluator::getField(const char*& expr)
|
||||
bool ExpEvaluator::getField(ParsePoint& expr)
|
||||
{
|
||||
if (inError())
|
||||
return false;
|
||||
XDebug(this,DebugAll,"getField '%.30s'",expr);
|
||||
XDebug(this,DebugAll,"getField '%.30s'",(const char*)expr);
|
||||
skipComments(expr);
|
||||
int len = getKeyword(expr);
|
||||
if (len <= 0)
|
||||
|
@ -487,19 +498,19 @@ bool ExpEvaluator::getField(const char*& expr)
|
|||
return true;
|
||||
}
|
||||
|
||||
ExpEvaluator::Opcode ExpEvaluator::getOperator(const char*& expr)
|
||||
ExpEvaluator::Opcode ExpEvaluator::getOperator(ParsePoint& expr)
|
||||
{
|
||||
skipComments(expr);
|
||||
return getOperator(expr,m_operators);
|
||||
}
|
||||
|
||||
ExpEvaluator::Opcode ExpEvaluator::getUnaryOperator(const char*& expr)
|
||||
ExpEvaluator::Opcode ExpEvaluator::getUnaryOperator(ParsePoint& expr)
|
||||
{
|
||||
skipComments(expr);
|
||||
return getOperator(expr,m_unaryOps);
|
||||
}
|
||||
|
||||
ExpEvaluator::Opcode ExpEvaluator::getPostfixOperator(const char*& expr, int priority)
|
||||
ExpEvaluator::Opcode ExpEvaluator::getPostfixOperator(ParsePoint& expr, int priority)
|
||||
{
|
||||
return OpcNone;
|
||||
}
|
||||
|
@ -573,7 +584,7 @@ bool ExpEvaluator::getRightAssoc(ExpEvaluator::Opcode oper) const
|
|||
}
|
||||
}
|
||||
|
||||
bool ExpEvaluator::getSeparator(const char*& expr, bool remove)
|
||||
bool ExpEvaluator::getSeparator(ParsePoint& expr, bool remove)
|
||||
{
|
||||
if (skipComments(expr) != ',')
|
||||
return false;
|
||||
|
@ -582,7 +593,7 @@ bool ExpEvaluator::getSeparator(const char*& expr, bool remove)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ExpEvaluator::runCompile(const char*& expr, char stop, GenObject* nested)
|
||||
bool ExpEvaluator::runCompile(ParsePoint& expr, char stop, GenObject* nested)
|
||||
{
|
||||
char buf[2];
|
||||
const char* stopStr = 0;
|
||||
|
@ -594,7 +605,7 @@ bool ExpEvaluator::runCompile(const char*& expr, char stop, GenObject* nested)
|
|||
return runCompile(expr,stopStr,nested);
|
||||
}
|
||||
|
||||
bool ExpEvaluator::runCompile(const char*& expr, const char* stop, GenObject* nested)
|
||||
bool ExpEvaluator::runCompile(ParsePoint& expr, const char* stop, GenObject* nested)
|
||||
{
|
||||
typedef struct {
|
||||
Opcode code;
|
||||
|
@ -603,7 +614,7 @@ bool ExpEvaluator::runCompile(const char*& expr, const char* stop, GenObject* ne
|
|||
StackedOpcode stack[10];
|
||||
unsigned int stackPos = 0;
|
||||
#ifdef DEBUG
|
||||
Debugger debug(DebugInfo,"runCompile()"," '%s' %p '%.30s'",TelEngine::c_safe(stop),nested,expr);
|
||||
Debugger debug(DebugInfo,"runCompile()"," '%s' %p '%.30s'",TelEngine::c_safe(stop),nested,(const char*)expr);
|
||||
#endif
|
||||
if (skipComments(expr) == ')')
|
||||
return false;
|
||||
|
@ -616,12 +627,15 @@ bool ExpEvaluator::runCompile(const char*& expr, const char* stop, GenObject* ne
|
|||
char stopChar = stop ? stop[0] : '\0';
|
||||
for (;;) {
|
||||
while (!stackPos && skipComments(expr) && (!stop || !::strchr(stop,*expr)) && getInstruction(expr,stopChar,nested))
|
||||
;
|
||||
if (expr.m_searchedSeps && expr.m_foundSep && ::strchr(expr.m_searchedSeps,expr.m_foundSep))
|
||||
return true;
|
||||
if (inError())
|
||||
return false;
|
||||
char c = skipComments(expr);
|
||||
if (c && stop && ::strchr(stop,c))
|
||||
if (c && stop && ::strchr(stop,c)) {
|
||||
expr.m_foundSep = c;
|
||||
return true;
|
||||
}
|
||||
if (!getOperand(expr))
|
||||
return false;
|
||||
Opcode oper;
|
||||
|
@ -1358,8 +1372,10 @@ bool ExpEvaluator::runAllFields(ObjList& stack, GenObject* context) const
|
|||
return ok;
|
||||
}
|
||||
|
||||
int ExpEvaluator::compile(const char* expr, GenObject* context)
|
||||
int ExpEvaluator::compile(ParsePoint& expr, GenObject* context)
|
||||
{
|
||||
if (!expr.m_eval)
|
||||
expr.m_eval = this;
|
||||
if (!skipComments(expr,context))
|
||||
return 0;
|
||||
int res = 0;
|
||||
|
|
|
@ -157,8 +157,8 @@ public:
|
|||
bool link();
|
||||
inline bool traceable() const
|
||||
{ return m_traceable; }
|
||||
JsObject* parseArray(const char*& expr, bool constOnly);
|
||||
JsObject* parseObject(const char*& expr, bool constOnly);
|
||||
JsObject* parseArray(ParsePoint& expr, bool constOnly);
|
||||
JsObject* parseObject(ParsePoint& expr, bool constOnly);
|
||||
inline const NamedList& pragmas() const
|
||||
{ return m_pragmas; }
|
||||
inline static unsigned int getLineNo(unsigned int line)
|
||||
|
@ -175,20 +175,20 @@ protected:
|
|||
{ m_traceable = allowed; }
|
||||
void setBaseFile(const String& file);
|
||||
virtual void formatLineNo(String& buf, unsigned int line) const;
|
||||
virtual bool getString(const char*& expr);
|
||||
virtual bool getString(ParsePoint& expr);
|
||||
virtual bool getEscape(const char*& expr, String& str, char sep);
|
||||
virtual bool keywordChar(char c) const;
|
||||
virtual int getKeyword(const char* str) const;
|
||||
virtual char skipComments(const char*& expr, GenObject* context = 0);
|
||||
virtual int preProcess(const char*& expr, GenObject* context = 0);
|
||||
virtual bool getInstruction(const char*& expr, char stop, GenObject* nested);
|
||||
virtual bool getSimple(const char*& expr, bool constOnly = false);
|
||||
virtual Opcode getOperator(const char*& expr);
|
||||
virtual Opcode getUnaryOperator(const char*& expr);
|
||||
virtual Opcode getPostfixOperator(const char*& expr, int precedence);
|
||||
virtual char skipComments(ParsePoint& expr, GenObject* context = 0);
|
||||
virtual int preProcess(ParsePoint& expr, GenObject* context = 0);
|
||||
virtual bool getInstruction(ParsePoint& expr, char stop, GenObject* nested);
|
||||
virtual bool getSimple(ParsePoint& expr, bool constOnly = false);
|
||||
virtual Opcode getOperator(ParsePoint& expr);
|
||||
virtual Opcode getUnaryOperator(ParsePoint& expr);
|
||||
virtual Opcode getPostfixOperator(ParsePoint& expr, int precedence);
|
||||
virtual const char* getOperator(Opcode oper) const;
|
||||
virtual int getPrecedence(ExpEvaluator::Opcode oper) const;
|
||||
virtual bool getSeparator(const char*& expr, bool remove);
|
||||
virtual bool getSeparator(ParsePoint& expr, bool remove);
|
||||
virtual bool runOperation(ObjList& stack, const ExpOperation& oper, GenObject* context) const;
|
||||
virtual bool runFunction(ObjList& stack, const ExpOperation& oper, GenObject* context) const;
|
||||
virtual bool runField(ObjList& stack, const ExpOperation& oper, GenObject* context) const;
|
||||
|
@ -198,17 +198,17 @@ private:
|
|||
ObjList m_included;
|
||||
ObjList m_globals;
|
||||
NamedList m_pragmas;
|
||||
bool preProcessInclude(const char*& expr, bool once, GenObject* context);
|
||||
bool preProcessPragma(const char*& expr, GenObject* context);
|
||||
bool getOneInstruction(const char*& expr, GenObject* nested);
|
||||
bool parseInner(const char*& expr, JsOpcode opcode, ParseNested* nested);
|
||||
bool parseIf(const char*& expr, GenObject* nested);
|
||||
bool parseSwitch(const char*& expr, GenObject* nested);
|
||||
bool parseFor(const char*& expr, GenObject* nested);
|
||||
bool parseWhile(const char*& expr, GenObject* nested);
|
||||
bool parseVar(const char*& expr);
|
||||
bool parseTry(const char*& expr, GenObject* nested);
|
||||
bool parseFuncDef(const char*& expr, bool publish);
|
||||
bool preProcessInclude(ParsePoint& expr, bool once, GenObject* context);
|
||||
bool preProcessPragma(ParsePoint& expr, GenObject* context);
|
||||
bool getOneInstruction(ParsePoint& expr, GenObject* nested);
|
||||
bool parseInner(ParsePoint& expr, JsOpcode opcode, ParseNested* nested);
|
||||
bool parseIf(ParsePoint& expr, GenObject* nested);
|
||||
bool parseSwitch(ParsePoint& expr, GenObject* nested);
|
||||
bool parseFor(ParsePoint& expr, GenObject* nested);
|
||||
bool parseWhile(ParsePoint& expr, GenObject* nested);
|
||||
bool parseVar(ParsePoint& expr);
|
||||
bool parseTry(ParsePoint& expr, GenObject* nested);
|
||||
bool parseFuncDef(ParsePoint& expr, bool publish);
|
||||
bool evalList(ObjList& stack, GenObject* context) const;
|
||||
bool evalVector(ObjList& stack, GenObject* context) const;
|
||||
bool jumpToLabel(long int label, GenObject* context) const;
|
||||
|
@ -391,13 +391,13 @@ public:
|
|||
{ return nested ? static_cast<ParseNested*>(nested)->find(opcode) : 0; }
|
||||
inline static ParseNested* findMatch(GenObject* nested, JsCode::JsOpcode opcode)
|
||||
{ return nested ? static_cast<ParseNested*>(nested)->findMatch(opcode) : 0; }
|
||||
static bool parseInner(GenObject* nested, JsCode::JsOpcode opcode, const char*& expr)
|
||||
static bool parseInner(GenObject* nested, JsCode::JsOpcode opcode, ParsePoint& expr)
|
||||
{ ParseNested* inner = findMatch(nested,opcode);
|
||||
return inner && inner->parseInner(expr,opcode); }
|
||||
protected:
|
||||
virtual bool isMatch(JsCode::JsOpcode opcode)
|
||||
{ return false; }
|
||||
inline bool parseInner(const char*& expr, JsCode::JsOpcode opcode)
|
||||
inline bool parseInner(ParsePoint& expr, JsCode::JsOpcode opcode)
|
||||
{ return m_code->parseInner(expr,opcode,this); }
|
||||
inline ParseNested* find(JsCode::JsOpcode opcode)
|
||||
{ return (opcode == m_opcode) ? this :
|
||||
|
@ -967,7 +967,7 @@ void JsCode::formatLineNo(String& buf, unsigned int line) const
|
|||
buf << (file ? file->toString().c_str() : "???") << ":" << (line & 0xffffff);
|
||||
}
|
||||
|
||||
bool JsCode::getString(const char*& expr)
|
||||
bool JsCode::getString(ParsePoint& expr)
|
||||
{
|
||||
if (inError())
|
||||
return false;
|
||||
|
@ -1102,7 +1102,7 @@ int JsCode::getKeyword(const char* str) const
|
|||
return len;
|
||||
}
|
||||
|
||||
char JsCode::skipComments(const char*& expr, GenObject* context)
|
||||
char JsCode::skipComments(ParsePoint& expr, GenObject* context)
|
||||
{
|
||||
char c = skipWhites(expr);
|
||||
while (c == '/') {
|
||||
|
@ -1138,7 +1138,7 @@ void JsCode::setBaseFile(const String& file)
|
|||
m_lineNo = ((idx + 1) << 24) | 1;
|
||||
}
|
||||
|
||||
bool JsCode::preProcessInclude(const char*& expr, bool once, GenObject* context)
|
||||
bool JsCode::preProcessInclude(ParsePoint& expr, bool once, GenObject* context)
|
||||
{
|
||||
if (m_depth > 5)
|
||||
return gotError("Possible recursive include");
|
||||
|
@ -1162,12 +1162,12 @@ bool JsCode::preProcessInclude(const char*& expr, bool once, GenObject* context)
|
|||
idx = m_included.index(s);
|
||||
}
|
||||
// use the upper bits of line # for file index
|
||||
unsigned int savedLine = m_lineNo;
|
||||
m_lineNo = ((idx + 1) << 24) | 1;
|
||||
unsigned int savedLine = expr.m_lineNo;
|
||||
expr.m_lineNo = m_lineNo = ((idx + 1) << 24) | 1;
|
||||
m_depth++;
|
||||
ok = parser->parseFile(str,true);
|
||||
m_depth--;
|
||||
m_lineNo = savedLine;
|
||||
expr.m_lineNo = m_lineNo = savedLine;
|
||||
}
|
||||
}
|
||||
return ok || gotError("Failed to include " + str);
|
||||
|
@ -1177,13 +1177,14 @@ bool JsCode::preProcessInclude(const char*& expr, bool once, GenObject* context)
|
|||
return gotError("Expecting include file",expr);
|
||||
}
|
||||
|
||||
bool JsCode::preProcessPragma(const char*& expr, GenObject* context)
|
||||
bool JsCode::preProcessPragma(ParsePoint& expr, GenObject* context)
|
||||
{
|
||||
skipComments(expr);
|
||||
int len = ExpEvaluator::getKeyword(expr);
|
||||
if (len <= 0)
|
||||
return gotError("Expecting pragma code",expr);
|
||||
const char* str = expr + len;
|
||||
ParsePoint str = expr;
|
||||
str += len;
|
||||
char c = skipComments(str);
|
||||
if (c == '"' || c == '\'') {
|
||||
String val;
|
||||
|
@ -1197,7 +1198,7 @@ bool JsCode::preProcessPragma(const char*& expr, GenObject* context)
|
|||
return gotError("Expecting pragma string",expr);
|
||||
}
|
||||
|
||||
int JsCode::preProcess(const char*& expr, GenObject* context)
|
||||
int JsCode::preProcess(ParsePoint& expr, GenObject* context)
|
||||
{
|
||||
int rval = -1;
|
||||
for (;;) {
|
||||
|
@ -1225,49 +1226,67 @@ int JsCode::preProcess(const char*& expr, GenObject* context)
|
|||
}
|
||||
}
|
||||
|
||||
bool JsCode::getOneInstruction(const char*& expr, GenObject* nested)
|
||||
bool JsCode::getOneInstruction(ParsePoint& expr, GenObject* nested)
|
||||
{
|
||||
if (inError())
|
||||
return false;
|
||||
XDebug(this,DebugAll,"JsCode::getOneInstruction %p '%.30s'",nested,expr);
|
||||
XDebug(this,DebugAll,"JsCode::getOneInstruction %p '%.30s'",nested,(const char*)expr);
|
||||
const char* savedSeps = expr.m_searchedSeps;
|
||||
if (skipComments(expr) == '{') {
|
||||
expr.m_searchedSeps = "}";
|
||||
if (!getInstruction(expr,0,nested))
|
||||
return false;
|
||||
}
|
||||
else if (!runCompile(expr,";}",nested))
|
||||
return false;
|
||||
else {
|
||||
expr.m_searchedSeps = ";}";
|
||||
if (!runCompile(expr,";}",nested))
|
||||
return false;
|
||||
if (skipComments(expr) == ';') {
|
||||
expr.m_foundSep = ';';
|
||||
expr++;
|
||||
}
|
||||
}
|
||||
expr.m_searchedSeps = savedSeps;
|
||||
if (!expr.m_searchedSeps || expr.m_count)
|
||||
expr.m_foundSep = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsCode::getInstruction(const char*& expr, char stop, GenObject* nested)
|
||||
bool JsCode::getInstruction(ParsePoint& expr, char stop, GenObject* nested)
|
||||
{
|
||||
if (inError())
|
||||
return false;
|
||||
XDebug(this,DebugAll,"JsCode::getInstruction %p '%.1s' '%.30s'",nested,&stop,expr);
|
||||
XDebug(this,DebugAll,"JsCode::getInstruction %p '%.1s' 'separators=%s' 'count=%u' '%.30s'",nested,&stop,expr.m_searchedSeps,
|
||||
expr.m_count,(const char*)expr);
|
||||
if (skipComments(expr) == '{') {
|
||||
if (stop == ')')
|
||||
return false;
|
||||
expr++;
|
||||
expr.m_count++;
|
||||
for (;;) {
|
||||
if (!runCompile(expr,'}',nested))
|
||||
return false;
|
||||
bool sep = false;
|
||||
while (skipComments(expr) && getSeparator(expr,true))
|
||||
sep = true;
|
||||
if (*expr == '}' || !sep)
|
||||
if (*expr.m_expr == '}' || !sep)
|
||||
break;
|
||||
}
|
||||
if (*expr != '}')
|
||||
return gotError("Expecting '}'",expr);
|
||||
expr++;
|
||||
expr.m_foundSep = '}';
|
||||
if (expr.m_count > 0)
|
||||
expr.m_count--;
|
||||
return true;
|
||||
}
|
||||
else if (*expr == ';') {
|
||||
expr++;
|
||||
expr.m_foundSep = ';';
|
||||
return true;
|
||||
}
|
||||
const char* saved = expr;
|
||||
unsigned int savedLine = m_lineNo;
|
||||
expr.m_foundSep = 0;
|
||||
ParsePoint saved = expr;
|
||||
Opcode op = ExpEvaluator::getOperator(expr,s_instr);
|
||||
switch ((JsOpcode)op) {
|
||||
case (JsOpcode)OpcNone:
|
||||
|
@ -1294,7 +1313,6 @@ bool JsCode::getInstruction(const char*& expr, char stop, GenObject* nested)
|
|||
return parseIf(expr,nested);
|
||||
case OpcElse:
|
||||
expr = saved;
|
||||
m_lineNo = savedLine;
|
||||
return false;
|
||||
case OpcSwitch:
|
||||
return parseSwitch(expr,nested);
|
||||
|
@ -1304,7 +1322,7 @@ bool JsCode::getInstruction(const char*& expr, char stop, GenObject* nested)
|
|||
return parseWhile(expr,nested);
|
||||
case OpcCase:
|
||||
if (!ParseNested::parseInner(nested,OpcCase,expr)) {
|
||||
m_lineNo = savedLine;
|
||||
expr.m_lineNo = saved.m_lineNo;
|
||||
return gotError("case not inside switch",saved);
|
||||
}
|
||||
if (skipComments(expr) != ':')
|
||||
|
@ -1313,7 +1331,7 @@ bool JsCode::getInstruction(const char*& expr, char stop, GenObject* nested)
|
|||
break;
|
||||
case OpcDefault:
|
||||
if (!ParseNested::parseInner(nested,OpcDefault,expr)) {
|
||||
m_lineNo = savedLine;
|
||||
expr.m_lineNo = saved.m_lineNo;
|
||||
return gotError("Unexpected default instruction",saved);
|
||||
}
|
||||
if (skipComments(expr) != ':')
|
||||
|
@ -1322,7 +1340,7 @@ bool JsCode::getInstruction(const char*& expr, char stop, GenObject* nested)
|
|||
break;
|
||||
case OpcBreak:
|
||||
if (!ParseNested::parseInner(nested,OpcBreak,expr)) {
|
||||
m_lineNo = savedLine;
|
||||
expr.m_lineNo = saved.m_lineNo;
|
||||
return gotError("Unexpected break instruction",saved);
|
||||
}
|
||||
if (skipComments(expr) != ';')
|
||||
|
@ -1330,7 +1348,7 @@ bool JsCode::getInstruction(const char*& expr, char stop, GenObject* nested)
|
|||
break;
|
||||
case OpcCont:
|
||||
if (!ParseNested::parseInner(nested,OpcCont,expr)) {
|
||||
m_lineNo = savedLine;
|
||||
expr.m_lineNo = saved.m_lineNo;
|
||||
return gotError("Unexpected continue instruction",saved);
|
||||
}
|
||||
if (skipComments(expr) != ';')
|
||||
|
@ -1391,7 +1409,7 @@ private:
|
|||
};
|
||||
|
||||
// Parse keywords inner to specific instructions
|
||||
bool JsCode::parseInner(const char*& expr, JsOpcode opcode, ParseNested* nested)
|
||||
bool JsCode::parseInner(ParsePoint& expr, JsOpcode opcode, ParseNested* nested)
|
||||
{
|
||||
switch (*nested) {
|
||||
case OpcFor:
|
||||
|
@ -1400,11 +1418,11 @@ bool JsCode::parseInner(const char*& expr, JsOpcode opcode, ParseNested* nested)
|
|||
ParseLoop* block = static_cast<ParseLoop*>(nested);
|
||||
switch (opcode) {
|
||||
case OpcBreak:
|
||||
XDebug(this,DebugAll,"Parsing loop:break '%.30s'",expr);
|
||||
XDebug(this,DebugAll,"Parsing loop:break '%.30s'",(const char*)expr);
|
||||
addOpcode((Opcode)OpcJump,block->m_lblBreak);
|
||||
break;
|
||||
case OpcCont:
|
||||
XDebug(this,DebugAll,"Parsing loop:continue '%.30s'",expr);
|
||||
XDebug(this,DebugAll,"Parsing loop:continue '%.30s'",(const char*)expr);
|
||||
addOpcode((Opcode)OpcJump,block->m_lblCont);
|
||||
break;
|
||||
default:
|
||||
|
@ -1421,7 +1439,7 @@ bool JsCode::parseInner(const char*& expr, JsOpcode opcode, ParseNested* nested)
|
|||
return gotError("Encountered case after default",expr);
|
||||
if (!getSimple(expr,true))
|
||||
return gotError("Expecting case constant",expr);
|
||||
XDebug(this,DebugAll,"Parsing switch:case: '%.30s'",expr);
|
||||
XDebug(this,DebugAll,"Parsing switch:case: '%.30s'",(const char*)expr);
|
||||
block->m_state = ParseSwitch::InCase;
|
||||
block->m_cases.append(popOpcode());
|
||||
addOpcode(OpcLabel,++m_label);
|
||||
|
@ -1430,13 +1448,13 @@ bool JsCode::parseInner(const char*& expr, JsOpcode opcode, ParseNested* nested)
|
|||
case OpcDefault:
|
||||
if (block->state() == ParseSwitch::InDefault)
|
||||
return gotError("Duplicate default case",expr);
|
||||
XDebug(this,DebugAll,"Parsing switch:default: '%.30s'",expr);
|
||||
XDebug(this,DebugAll,"Parsing switch:default: '%.30s'",(const char*)expr);
|
||||
block->m_state = ParseSwitch::InDefault;
|
||||
block->m_lblDefault = ++m_label;
|
||||
addOpcode(OpcLabel,block->m_lblDefault);
|
||||
break;
|
||||
case OpcBreak:
|
||||
XDebug(this,DebugAll,"Parsing switch:break '%.30s'",expr);
|
||||
XDebug(this,DebugAll,"Parsing switch:break '%.30s'",(const char*)expr);
|
||||
addOpcode((Opcode)OpcJump,static_cast<ParseSwitch*>(nested)->m_lblBreak);
|
||||
break;
|
||||
default:
|
||||
|
@ -1450,8 +1468,9 @@ bool JsCode::parseInner(const char*& expr, JsOpcode opcode, ParseNested* nested)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool JsCode::parseIf(const char*& expr, GenObject* nested)
|
||||
bool JsCode::parseIf(ParsePoint& expr, GenObject* nested)
|
||||
{
|
||||
XDebug(this,DebugAll,"JsCode::parseIf() '%.30s'",(const char*)expr);
|
||||
if (skipComments(expr) != '(')
|
||||
return gotError("Expecting '('",expr);
|
||||
if (!runCompile(++expr,')'))
|
||||
|
@ -1463,10 +1482,7 @@ bool JsCode::parseIf(const char*& expr, GenObject* nested)
|
|||
if (!getOneInstruction(expr,nested))
|
||||
return false;
|
||||
skipComments(expr);
|
||||
const char* save = expr;
|
||||
unsigned int savedLine = m_lineNo;
|
||||
if (*expr == ';')
|
||||
skipComments(++expr);
|
||||
ParsePoint save = expr;
|
||||
if ((JsOpcode)ExpEvaluator::getOperator(expr,s_instr) == OpcElse) {
|
||||
ExpOperation* jump = addOpcode((Opcode)OpcJump,++m_label);
|
||||
addOpcode(OpcLabel,cond->number());
|
||||
|
@ -1476,13 +1492,12 @@ bool JsCode::parseIf(const char*& expr, GenObject* nested)
|
|||
}
|
||||
else {
|
||||
expr = save;
|
||||
m_lineNo = savedLine;
|
||||
addOpcode(OpcLabel,cond->number());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsCode::parseSwitch(const char*& expr, GenObject* nested)
|
||||
bool JsCode::parseSwitch(ParsePoint& expr, GenObject* nested)
|
||||
{
|
||||
if (skipComments(expr) != '(')
|
||||
return gotError("Expecting '('",expr);
|
||||
|
@ -1494,6 +1509,8 @@ bool JsCode::parseSwitch(const char*& expr, GenObject* nested)
|
|||
if (skipComments(++expr) != '{')
|
||||
return gotError("Expecting '{'",expr);
|
||||
expr++;
|
||||
const char* savedSeps = expr.m_searchedSeps;
|
||||
expr.m_searchedSeps = "";
|
||||
ExpOperation* jump = addOpcode((Opcode)OpcJump,++m_label);
|
||||
ParseSwitch parseStack(this,nested,++m_label);
|
||||
for (;;) {
|
||||
|
@ -1508,6 +1525,9 @@ bool JsCode::parseSwitch(const char*& expr, GenObject* nested)
|
|||
if (*expr != '}')
|
||||
return gotError("Expecting '}'",expr);
|
||||
expr++;
|
||||
expr.m_searchedSeps = savedSeps;
|
||||
if (!expr.m_searchedSeps || expr.m_count)
|
||||
expr.m_foundSep = 0;
|
||||
// implicit break at end
|
||||
addOpcode((Opcode)OpcJump,parseStack.m_lblBreak);
|
||||
addOpcode(OpcLabel,jump->number());
|
||||
|
@ -1528,7 +1548,7 @@ bool JsCode::parseSwitch(const char*& expr, GenObject* nested)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool JsCode::parseFor(const char*& expr, GenObject* nested)
|
||||
bool JsCode::parseFor(ParsePoint& expr, GenObject* nested)
|
||||
{
|
||||
if (skipComments(expr) != '(')
|
||||
return gotError("Expecting '('",expr);
|
||||
|
@ -1585,7 +1605,7 @@ bool JsCode::parseFor(const char*& expr, GenObject* nested)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool JsCode::parseWhile(const char*& expr, GenObject* nested)
|
||||
bool JsCode::parseWhile(ParsePoint& expr, GenObject* nested)
|
||||
{
|
||||
if (skipComments(expr) != '(')
|
||||
return gotError("Expecting '('",expr);
|
||||
|
@ -1607,11 +1627,11 @@ bool JsCode::parseWhile(const char*& expr, GenObject* nested)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool JsCode::parseVar(const char*& expr)
|
||||
bool JsCode::parseVar(ParsePoint& expr)
|
||||
{
|
||||
if (inError())
|
||||
return false;
|
||||
XDebug(this,DebugAll,"parseVar '%.30s'",expr);
|
||||
XDebug(this,DebugAll,"parseVar '%.30s'",(const char*)expr);
|
||||
skipComments(expr);
|
||||
int len = ExpEvaluator::getKeyword(expr);
|
||||
if (len <= 0 || expr[len] == '(')
|
||||
|
@ -1624,7 +1644,7 @@ bool JsCode::parseVar(const char*& expr)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool JsCode::parseTry(const char*& expr, GenObject* nested)
|
||||
bool JsCode::parseTry(ParsePoint& expr, GenObject* nested)
|
||||
{
|
||||
addOpcode((Opcode)OpcTry);
|
||||
ParseNested parseStack(this,nested,OpcTry);
|
||||
|
@ -1649,9 +1669,9 @@ bool JsCode::parseTry(const char*& expr, GenObject* nested)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool JsCode::parseFuncDef(const char*& expr, bool publish)
|
||||
bool JsCode::parseFuncDef(ParsePoint& expr, bool publish)
|
||||
{
|
||||
XDebug(this,DebugAll,"JsCode::parseFuncDef '%.30s'",expr);
|
||||
XDebug(this,DebugAll,"JsCode::parseFuncDef '%.30s'",(const char*)expr);
|
||||
skipComments(expr);
|
||||
int len = getKeyword(expr);
|
||||
String name;
|
||||
|
@ -1700,11 +1720,11 @@ bool JsCode::parseFuncDef(const char*& expr, bool publish)
|
|||
return true;
|
||||
}
|
||||
|
||||
ExpEvaluator::Opcode JsCode::getOperator(const char*& expr)
|
||||
ExpEvaluator::Opcode JsCode::getOperator(ParsePoint& expr)
|
||||
{
|
||||
if (inError())
|
||||
return OpcNone;
|
||||
XDebug(this,DebugAll,"JsCode::getOperator '%.30s'",expr);
|
||||
XDebug(this,DebugAll,"JsCode::getOperator '%.30s'",(const char*)expr);
|
||||
skipComments(expr);
|
||||
Opcode op = ExpEvaluator::getOperator(expr,s_operators);
|
||||
if (OpcNone != op)
|
||||
|
@ -1712,11 +1732,11 @@ ExpEvaluator::Opcode JsCode::getOperator(const char*& expr)
|
|||
return ExpEvaluator::getOperator(expr);
|
||||
}
|
||||
|
||||
ExpEvaluator::Opcode JsCode::getUnaryOperator(const char*& expr)
|
||||
ExpEvaluator::Opcode JsCode::getUnaryOperator(ParsePoint& expr)
|
||||
{
|
||||
if (inError())
|
||||
return OpcNone;
|
||||
XDebug(this,DebugAll,"JsCode::getUnaryOperator '%.30s'",expr);
|
||||
XDebug(this,DebugAll,"JsCode::getUnaryOperator '%.30s'",(const char*)expr);
|
||||
skipComments(expr);
|
||||
Opcode op = ExpEvaluator::getOperator(expr,s_unaryOps);
|
||||
if (OpcNone != op)
|
||||
|
@ -1724,11 +1744,11 @@ ExpEvaluator::Opcode JsCode::getUnaryOperator(const char*& expr)
|
|||
return ExpEvaluator::getUnaryOperator(expr);
|
||||
}
|
||||
|
||||
ExpEvaluator::Opcode JsCode::getPostfixOperator(const char*& expr, int precedence)
|
||||
ExpEvaluator::Opcode JsCode::getPostfixOperator(ParsePoint& expr, int precedence)
|
||||
{
|
||||
if (inError())
|
||||
return OpcNone;
|
||||
XDebug(this,DebugAll,"JsCode::getPostfixOperator '%.30s'",expr);
|
||||
XDebug(this,DebugAll,"JsCode::getPostfixOperator '%.30s'",(const char*)expr);
|
||||
if (skipComments(expr) == '[') {
|
||||
// The Indexing operator has maximum priority!
|
||||
// No need to check it.
|
||||
|
@ -1742,14 +1762,12 @@ ExpEvaluator::Opcode JsCode::getPostfixOperator(const char*& expr, int precedenc
|
|||
return (Opcode)OpcIndex;
|
||||
}
|
||||
skipComments(expr);
|
||||
const char* save = expr;
|
||||
unsigned int savedLine = m_lineNo;
|
||||
ParsePoint save = expr;
|
||||
Opcode op = ExpEvaluator::getOperator(expr,s_postfixOps);
|
||||
if (OpcNone != op) {
|
||||
if (getPrecedence(op) >= precedence)
|
||||
return op;
|
||||
expr = save;
|
||||
m_lineNo = savedLine;
|
||||
return OpcNone;
|
||||
}
|
||||
return ExpEvaluator::getPostfixOperator(expr,precedence);
|
||||
|
@ -1795,13 +1813,14 @@ int JsCode::getPrecedence(ExpEvaluator::Opcode oper) const
|
|||
}
|
||||
}
|
||||
|
||||
bool JsCode::getSeparator(const char*& expr, bool remove)
|
||||
bool JsCode::getSeparator(ParsePoint& expr, bool remove)
|
||||
{
|
||||
if (inError())
|
||||
return false;
|
||||
switch (skipComments(expr)) {
|
||||
case ']':
|
||||
case ';':
|
||||
expr.m_foundSep =';';
|
||||
case ']':
|
||||
if (remove)
|
||||
expr++;
|
||||
return true;
|
||||
|
@ -1809,14 +1828,13 @@ bool JsCode::getSeparator(const char*& expr, bool remove)
|
|||
return ExpEvaluator::getSeparator(expr,remove);
|
||||
}
|
||||
|
||||
bool JsCode::getSimple(const char*& expr, bool constOnly)
|
||||
bool JsCode::getSimple(ParsePoint& expr, bool constOnly)
|
||||
{
|
||||
if (inError())
|
||||
return false;
|
||||
XDebug(this,DebugAll,"JsCode::getSimple(%s) '%.30s'",String::boolText(constOnly),expr);
|
||||
XDebug(this,DebugAll,"JsCode::getSimple(%s) '%.30s'",String::boolText(constOnly),(const char*)expr);
|
||||
skipComments(expr);
|
||||
const char* save = expr;
|
||||
unsigned int savedLine = m_lineNo;
|
||||
ParsePoint save = expr;
|
||||
switch ((JsOpcode)ExpEvaluator::getOperator(expr,s_constants)) {
|
||||
case OpcFalse:
|
||||
addOpcode(false);
|
||||
|
@ -1833,7 +1851,6 @@ bool JsCode::getSimple(const char*& expr, bool constOnly)
|
|||
case OpcFuncDef:
|
||||
if (constOnly) {
|
||||
expr = save;
|
||||
m_lineNo = savedLine;
|
||||
return false;
|
||||
}
|
||||
return parseFuncDef(expr,false);
|
||||
|
@ -1850,7 +1867,7 @@ bool JsCode::getSimple(const char*& expr, bool constOnly)
|
|||
}
|
||||
|
||||
// Parse an inline Javascript Array: [ item1, item2, ... ]
|
||||
JsObject* JsCode::parseArray(const char*& expr, bool constOnly)
|
||||
JsObject* JsCode::parseArray(ParsePoint& expr, bool constOnly)
|
||||
{
|
||||
if (skipComments(expr) != '[')
|
||||
return 0;
|
||||
|
@ -1883,7 +1900,7 @@ JsObject* JsCode::parseArray(const char*& expr, bool constOnly)
|
|||
|
||||
|
||||
// Parse an inline Javascript Object: { prop1: value1, "prop 2": value2, ... }
|
||||
JsObject* JsCode::parseObject(const char*& expr, bool constOnly)
|
||||
JsObject* JsCode::parseObject(ParsePoint& expr, bool constOnly)
|
||||
{
|
||||
if (skipComments(expr) != '{')
|
||||
return 0;
|
||||
|
@ -3267,14 +3284,18 @@ bool JsParser::parse(const char* text, bool fragment, const char* file)
|
|||
if (TelEngine::null(text))
|
||||
return false;
|
||||
String::stripBOM(text);
|
||||
ParsePoint expr(text,0,0,file);
|
||||
if (fragment)
|
||||
return code() && static_cast<JsCode*>(code())->compile(text,this);
|
||||
return code() && static_cast<JsCode*>(code())->compile(expr,this);
|
||||
JsCode* code = new JsCode;
|
||||
setCode(code);
|
||||
code->deref();
|
||||
if (!TelEngine::null(file))
|
||||
expr.m_eval = code;
|
||||
if (!TelEngine::null(file)) {
|
||||
code->setBaseFile(file);
|
||||
if (!code->compile(text,this)) {
|
||||
expr.m_fileName = file;
|
||||
}
|
||||
if (!code->compile(expr,this)) {
|
||||
setCode(0);
|
||||
return false;
|
||||
}
|
||||
|
@ -3307,7 +3328,8 @@ ScriptRun::Status JsParser::eval(const String& text, ExpOperation** result, Scri
|
|||
JsObject* JsParser::parseJSON(const char* text)
|
||||
{
|
||||
JsCode* code = new JsCode;
|
||||
JsObject* jso = code->parseObject(text,true);
|
||||
ParsePoint pp(text,code);
|
||||
JsObject* jso = code->parseObject(pp,true);
|
||||
TelEngine::destruct(code);
|
||||
return jso;
|
||||
}
|
||||
|
|
|
@ -116,12 +116,115 @@ public:
|
|||
virtual bool runAssign(ObjList& stack, const ExpOperation& oper, GenObject* context);
|
||||
};
|
||||
|
||||
/**
|
||||
* A class used to keep a parsing context
|
||||
* @short The parsing context
|
||||
*/
|
||||
class YSCRIPT_API ParsePoint
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
* @param expr Expression to be parsed
|
||||
* @param eval ExpEvaluator associated with this parsing context
|
||||
* @param lineNo The line number that is currently parsed
|
||||
* @param fileName File name associated with this context
|
||||
* @param seps Searched separator during parsing
|
||||
*/
|
||||
explicit inline ParsePoint(const char*& expr, ExpEvaluator* eval = 0, unsigned int lineNo = 0,
|
||||
const char* fileName = 0, const char* seps = 0)
|
||||
: m_expr(expr), m_searchedSeps(seps), m_count(0), m_foundSep(0), m_lineNo(lineNo), m_eval(eval), m_fileName(fileName)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* Assignment operator
|
||||
* @param parsePoint Parsing context which is to be assigned to this parsing context
|
||||
*/
|
||||
ParsePoint& operator=(ParsePoint& parsePoint);
|
||||
|
||||
/**
|
||||
* Cast operator to const char*&
|
||||
*/
|
||||
inline operator const char*&()
|
||||
{ return m_expr; }
|
||||
|
||||
/**
|
||||
* Assignement from const char*
|
||||
*/
|
||||
inline ParsePoint& operator=(const char* newExpr)
|
||||
{
|
||||
m_expr = newExpr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefix incrementation operator. Incrementes the internal expression
|
||||
*/
|
||||
inline ParsePoint& operator++() // prefix
|
||||
{
|
||||
++m_expr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Postfix incrementation operator. Incrementes the internal expression
|
||||
*/
|
||||
inline ParsePoint& operator++(int unused) // postfix
|
||||
{
|
||||
++m_expr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get first char in the parsed expression
|
||||
* @return First char in the expression to be parsed
|
||||
*/
|
||||
inline char firstChar()
|
||||
{ return *m_expr; }
|
||||
|
||||
/**
|
||||
* Expression to be parsed
|
||||
*/
|
||||
const char* m_expr;
|
||||
|
||||
/**
|
||||
* Searched instruction separators
|
||||
*/
|
||||
const char* m_searchedSeps;
|
||||
|
||||
/**
|
||||
* Number of how many times the parser must encouter a separator
|
||||
*/
|
||||
unsigned int m_count;
|
||||
|
||||
/**
|
||||
* Separator that the parser encountered
|
||||
*/
|
||||
char m_foundSep;
|
||||
|
||||
/**
|
||||
* Line numbet at which parsing is taking place
|
||||
*/
|
||||
unsigned int m_lineNo;
|
||||
|
||||
/**
|
||||
* ExpEvaluator associated with this parsing context
|
||||
*/
|
||||
ExpEvaluator* m_eval;
|
||||
|
||||
/**
|
||||
* File name associated for this context
|
||||
*/
|
||||
String m_fileName;
|
||||
};
|
||||
|
||||
/**
|
||||
* A class used to build stack based (posifix) expression parsers and evaluators
|
||||
* @short An expression parser and evaluator
|
||||
*/
|
||||
class YSCRIPT_API ExpEvaluator : public DebugEnabler
|
||||
{
|
||||
friend class ParsePoint;
|
||||
public:
|
||||
/**
|
||||
* Parsing styles
|
||||
|
@ -229,11 +332,11 @@ public:
|
|||
|
||||
/**
|
||||
* Parse and compile an expression
|
||||
* @param expr Pointer to expression to compile
|
||||
* @param expr Parsing context to compile
|
||||
* @param context Pointer to arbitrary object to be passed to called methods
|
||||
* @return Number of expressions compiled, zero on error
|
||||
*/
|
||||
int compile(const char* expr, GenObject* context = 0);
|
||||
int compile(ParsePoint& expr, GenObject* context = 0);
|
||||
|
||||
/**
|
||||
* Evaluate the expression, optionally return results
|
||||
|
@ -413,10 +516,10 @@ public:
|
|||
protected:
|
||||
/**
|
||||
* Method to skip over whitespaces, count parsed lines too
|
||||
* @param expr Pointer to expression cursor, gets advanced
|
||||
* @param expr Current parsing context, advances on expression to be compiled
|
||||
* @return First character after whitespaces where expr points
|
||||
*/
|
||||
virtual char skipWhites(const char*& expr);
|
||||
virtual char skipWhites(ParsePoint& expr);
|
||||
|
||||
/**
|
||||
* Helper method to conditionally convert to lower case
|
||||
|
@ -495,59 +598,59 @@ protected:
|
|||
|
||||
/**
|
||||
* Runs the parser and compiler for one (sub)expression
|
||||
* @param expr Pointer to text to parse, gets advanced
|
||||
* @param expr Current parsing context, advances on expression to be compiled
|
||||
* @param stop Optional character expected after the expression
|
||||
* @param nested User defined object to pass for nested parsing
|
||||
* @return True if one expression was compiled and a separator follows
|
||||
*/
|
||||
bool runCompile(const char*& expr, char stop, GenObject* nested = 0);
|
||||
bool runCompile(ParsePoint& expr, char stop, GenObject* nested = 0);
|
||||
|
||||
/**
|
||||
* Runs the parser and compiler for one (sub)expression
|
||||
* @param expr Pointer to text to parse, gets advanced
|
||||
* @param expr Current parsing context, advances on expression to be compiled
|
||||
* @param stop Optional list of possible characters expected after the expression
|
||||
* @param nested User defined object to pass for nested parsing
|
||||
* @return True if one expression was compiled and a separator follows
|
||||
*/
|
||||
virtual bool runCompile(const char*& expr, const char* stop = 0, GenObject* nested = 0);
|
||||
virtual bool runCompile(ParsePoint& expr, const char* stop = 0, GenObject* nested = 0);
|
||||
|
||||
/**
|
||||
* Skip over comments and whitespaces
|
||||
* @param expr Pointer to expression cursor, gets advanced
|
||||
* @param expr Current parsing context, advances on expression to be compiled
|
||||
* @param context Pointer to arbitrary object to be passed to called methods
|
||||
* @return First character after comments or whitespaces where expr points
|
||||
*/
|
||||
virtual char skipComments(const char*& expr, GenObject* context = 0);
|
||||
virtual char skipComments(ParsePoint& expr, GenObject* context = 0);
|
||||
|
||||
/**
|
||||
* Process top-level preprocessor directives
|
||||
* @param expr Pointer to expression cursor, gets advanced
|
||||
* @param expr Current parsing context, advances on expression to be compiled
|
||||
* @param context Pointer to arbitrary object to be passed to called methods
|
||||
* @return Number of expressions compiled, negative if no more directives
|
||||
*/
|
||||
virtual int preProcess(const char*& expr, GenObject* context = 0);
|
||||
virtual int preProcess(ParsePoint& expr, GenObject* context = 0);
|
||||
|
||||
/**
|
||||
* Returns next operator in the parsed text
|
||||
* @param expr Pointer to text to parse, gets advanced if succeeds
|
||||
* @param expr Current parsing context, advances on expression to be compiled if it succeeds
|
||||
* @return Operator code, OpcNone on failure
|
||||
*/
|
||||
virtual Opcode getOperator(const char*& expr);
|
||||
virtual Opcode getOperator(ParsePoint& expr);
|
||||
|
||||
/**
|
||||
* Returns next unary operator in the parsed text
|
||||
* @param expr Pointer to text to parse, gets advanced if succeeds
|
||||
* @param expr Current parsing context, advances on expression to be compiled if it succeeds
|
||||
* @return Operator code, OpcNone on failure
|
||||
*/
|
||||
virtual Opcode getUnaryOperator(const char*& expr);
|
||||
virtual Opcode getUnaryOperator(ParsePoint& expr);
|
||||
|
||||
/**
|
||||
* Returns next unary postfix operator in the parsed text
|
||||
* @param expr Pointer to text to parse, gets advanced if succeeds
|
||||
* @param expr Current parsing context, advances on expression to be compiled if it succeeds
|
||||
* @param precedence The precedence of the previous operator
|
||||
* @return Operator code, OpcNone on failure
|
||||
*/
|
||||
virtual Opcode getPostfixOperator(const char*& expr, int precedence = 0);
|
||||
virtual Opcode getPostfixOperator(ParsePoint& expr, int precedence = 0);
|
||||
|
||||
/**
|
||||
* Helper method to get the canonical name of an operator
|
||||
|
@ -572,58 +675,58 @@ protected:
|
|||
|
||||
/**
|
||||
* Check if we are at an expression separator and optionally skip past it
|
||||
* @param expr Pointer to text to check, gets advanced if asked to remove separator
|
||||
* @param expr Current parsing context to check, advances on expression to be compiled if asked to remove separator
|
||||
* @param remove True to skip past the found separator
|
||||
* @return True if a separator was found
|
||||
*/
|
||||
virtual bool getSeparator(const char*& expr, bool remove);
|
||||
virtual bool getSeparator(ParsePoint& expr, bool remove);
|
||||
|
||||
/**
|
||||
* Get an instruction or block, advance parsing pointer past it
|
||||
* @param expr Pointer to text to parse, gets advanced on success
|
||||
* @param expr Current parsing context, advances on expression to be compiled if it succeeds
|
||||
* @param stop Optional character expected after the instruction
|
||||
* @param nested User defined object passed from nested parsing
|
||||
* @return True if succeeded, must add the operands internally
|
||||
*/
|
||||
virtual bool getInstruction(const char*& expr, char stop = 0, GenObject* nested = 0);
|
||||
virtual bool getInstruction(ParsePoint& expr, char stop = 0, GenObject* nested = 0);
|
||||
|
||||
/**
|
||||
* Get an operand, advance parsing pointer past it
|
||||
* @param expr Pointer to text to parse, gets advanced on success
|
||||
* @param expr Current parsing context, advances on expression to be compiled if it succeeds
|
||||
* @param endOk Consider reaching the end of string a success
|
||||
* @param precedence The precedence of the previous operator
|
||||
* @return True if succeeded, must add the operand internally
|
||||
*/
|
||||
virtual bool getOperand(const char*& expr, bool endOk = true, int precedence = 0);
|
||||
virtual bool getOperand(ParsePoint& expr, bool endOk = true, int precedence = 0);
|
||||
|
||||
/**
|
||||
* Get an inline simple type, usually string or number
|
||||
* @param expr Pointer to text to parse, gets advanced on success
|
||||
* @param expr Current parsing context, advances on expression to be compiled if it succeeds
|
||||
* @param constOnly Return only inline constants
|
||||
* @return True if succeeded, must add the operand internally
|
||||
*/
|
||||
virtual bool getSimple(const char*& expr, bool constOnly = false);
|
||||
virtual bool getSimple(ParsePoint& expr, bool constOnly = false);
|
||||
|
||||
/**
|
||||
* Get a numerical operand, advance parsing pointer past it
|
||||
* @param expr Pointer to text to parse, gets advanced on success
|
||||
* @param expr Current parsing context, advances on expression to be compiled if it succeeds
|
||||
* @return True if succeeded, must add the operand internally
|
||||
*/
|
||||
virtual bool getNumber(const char*& expr);
|
||||
virtual bool getNumber(ParsePoint& expr);
|
||||
|
||||
/**
|
||||
* Get a string operand, advance parsing pointer past it
|
||||
* @param expr Pointer to text to parse, gets advanced on success
|
||||
* @param expr Current parsing context, advances on expression to be compiled if it succeeds
|
||||
* @return True if succeeded, must add the operand internally
|
||||
*/
|
||||
virtual bool getString(const char*& expr);
|
||||
virtual bool getString(ParsePoint& expr);
|
||||
|
||||
/**
|
||||
* Get a function call, advance parsing pointer past it
|
||||
* @param expr Pointer to text to parse, gets advanced on success
|
||||
* @param expr Current parsing context, advances on expression to be compiled if it succeeds
|
||||
* @return True if succeeded, must add the operand internally
|
||||
*/
|
||||
virtual bool getFunction(const char*& expr);
|
||||
virtual bool getFunction(ParsePoint& expr);
|
||||
|
||||
/**
|
||||
* Helper method - get a string, advance parsing pointer past it
|
||||
|
@ -644,10 +747,10 @@ protected:
|
|||
|
||||
/**
|
||||
* Get a field keyword, advance parsing pointer past it
|
||||
* @param expr Pointer to text to parse, gets advanced on success
|
||||
* @param expr Current parsing context, advances on expression to be compiled if it succeeds
|
||||
* @return True if succeeded, must add the operand internally
|
||||
*/
|
||||
virtual bool getField(const char*& expr);
|
||||
virtual bool getField(ParsePoint& expr);
|
||||
|
||||
/**
|
||||
* Add an aready built operation to the expression and set its line number
|
||||
|
@ -804,7 +907,7 @@ protected:
|
|||
unsigned int m_lineNo;
|
||||
|
||||
private:
|
||||
bool getOperandInternal(const char*& expr, bool endOk, int precedence);
|
||||
bool getOperandInternal(ParsePoint& expr, bool endOk, int precedence);
|
||||
ExpExtender* m_extender;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue