Pass objects for parsing nested instructions in expressions.

Added specific Javascript parsers for nested instructions.


git-svn-id: http://voip.null.ro/svn/yate@5091 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
paulc 2012-06-04 18:06:39 +00:00
parent 8094964bc3
commit 7f5b22b1b6
3 changed files with 146 additions and 47 deletions

View File

@ -293,7 +293,7 @@ void ExpEvaluator::formatLineNo(String& buf, unsigned int line) const
buf << "line " << line;
}
bool ExpEvaluator::getInstruction(const char*& expr, Opcode nested)
bool ExpEvaluator::getInstruction(const char*& expr, GenObject* nested)
{
return false;
}
@ -570,7 +570,7 @@ bool ExpEvaluator::getSeparator(const char*& expr, bool remove)
return true;
}
bool ExpEvaluator::runCompile(const char*& expr, char stop, Opcode nested)
bool ExpEvaluator::runCompile(const char*& expr, char stop, GenObject* nested)
{
typedef struct {
Opcode code;
@ -579,7 +579,7 @@ bool ExpEvaluator::runCompile(const char*& expr, char stop, Opcode nested)
StackedOpcode stack[10];
unsigned int stackPos = 0;
#ifdef DEBUG
Debugger debug(DebugInfo,"runCompile()"," '%.1s' %u '%.30s'",&stop,nested,expr);
Debugger debug(DebugInfo,"runCompile()"," '%.1s' %p '%.30s'",&stop,nested,expr);
#endif
if (skipComments(expr) == ')')
return false;

View File

@ -28,6 +28,8 @@ using namespace TelEngine;
namespace { // anonymous
class ParseNested;
class JsContext : public JsObject, public Mutex
{
YCLASS(JsContext,JsObject)
@ -75,6 +77,7 @@ protected:
class JsCode : public ScriptCode, public ExpEvaluator
{
friend class ParseNested;
public:
enum JsOpcode {
OpcBegin = OpcPrivate + 1,
@ -141,7 +144,7 @@ protected:
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, Opcode nested);
virtual bool getInstruction(const char*& expr, GenObject* nested);
virtual bool getSimple(const char*& expr, bool constOnly = false);
virtual Opcode getOperator(const char*& expr);
virtual Opcode getUnaryOperator(const char*& expr);
@ -157,12 +160,13 @@ private:
ObjVector m_linked;
ObjList m_included;
bool preProcessInclude(const char*& expr, bool once, GenObject* context);
bool parseIf(const char*& expr, Opcode nested);
bool parseSwitch(const char*& expr, Opcode nested);
bool parseFor(const char*& expr, Opcode nested);
bool parseWhile(const char*& expr, Opcode nested);
bool parseTry(const char*& expr, Opcode nested);
bool parseFuncDef(const char*& expr, Opcode 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 parseTry(const char*& expr, GenObject* nested);
bool parseFuncDef(const char*& expr, GenObject* nested);
bool evalList(ObjList& stack, GenObject* context) const;
bool evalVector(ObjList& stack, GenObject* context) const;
bool jumpToLabel(long int label, GenObject* context) const;
@ -187,6 +191,45 @@ private:
unsigned int m_index;
};
class ParseNested : public GenObject
{
YCLASS(ParseNested,GenObject)
public:
inline explicit ParseNested(JsCode* code, GenObject* nested,
JsCode::JsOpcode oper = (JsCode::JsOpcode)ExpEvaluator::OpcNone)
: m_code(code), m_nested(static_cast<ParseNested*>(nested)), m_opcode(oper)
{ }
inline operator GenObject*()
{ return this; }
inline operator JsCode::JsOpcode() const
{ return m_opcode; }
inline static JsCode::JsOpcode code(GenObject* nested)
{ return nested ? *static_cast<ParseNested*>(nested) :
(JsCode::JsOpcode)ExpEvaluator::OpcNone; }
inline static ParseNested* find(GenObject* nested, JsCode::JsOpcode opcode)
{ 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)
{ 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)
{ return m_code->parseInner(expr,opcode,this); }
inline ParseNested* find(JsCode::JsOpcode opcode)
{ return (opcode == m_opcode) ? this :
(m_nested ? m_nested->find(opcode) : 0); }
inline ParseNested* findMatch(JsCode::JsOpcode opcode)
{ return isMatch(opcode) ? this :
(m_nested ? m_nested->findMatch(opcode) : 0); }
private:
JsCode* m_code;
ParseNested* m_nested;
JsCode::JsOpcode m_opcode;
};
#define MAKEOP(s,o) { s, JsCode::Opc ## o }
static const TokenDict s_operators[] =
{
@ -775,11 +818,11 @@ int JsCode::preProcess(const char*& expr, GenObject* context)
}
}
bool JsCode::getInstruction(const char*& expr, Opcode nested)
bool JsCode::getInstruction(const char*& expr, GenObject* nested)
{
if (inError())
return false;
XDebug(this,DebugAll,"JsCode::getInstruction '%.30s' %u",expr,nested);
XDebug(this,DebugAll,"JsCode::getInstruction '%.30s' %p",expr,nested);
if (skipComments(expr) == '{') {
expr++;
for (;;) {
@ -825,42 +868,29 @@ bool JsCode::getInstruction(const char*& expr, Opcode nested)
case OpcWhile:
return parseWhile(expr,nested);
case OpcCase:
if (OpcSwitch != (JsOpcode)nested)
return gotError("Case not in switch",saved);
if (!ExpEvaluator::getSimple(expr,true))
return gotError("Expecting case constant",expr);
if (!ParseNested::parseInner(nested,OpcCase,expr))
return gotError("case not inside switch",saved);
if (skipComments(expr) != ':')
return gotError("Expecting ':'",expr);
expr++;
break;
case OpcDefault:
if (OpcSwitch != (JsOpcode)nested)
return gotError("Default not in switch",saved);
if (!ParseNested::parseInner(nested,OpcDefault,expr))
return gotError("Unexpected default instruction",saved);
if (skipComments(expr) != ':')
return gotError("Expecting ':'",expr);
expr++;
break;
case OpcBreak:
switch ((JsOpcode)nested) {
case OpcSwitch:
case OpcFor:
case OpcWhile:
break;
default:
return gotError("Unexpected break instruction",saved);
}
if (!ParseNested::parseInner(nested,OpcBreak,expr))
return gotError("Unexpected break instruction",saved);
if (skipComments(expr) != ';')
return gotError("Expecting ';'",expr);
expr++;
break;
case OpcCont:
switch ((JsOpcode)nested) {
case OpcFor:
case OpcWhile:
break;
default:
return gotError("Unexpected continue instruction",saved);
}
if (!ParseNested::parseInner(nested,OpcCont,expr))
return gotError("Unexpected continue instruction",saved);
if (skipComments(expr) != ';')
return gotError("Expecting ';'",expr);
expr++;
@ -875,7 +905,72 @@ bool JsCode::getInstruction(const char*& expr, Opcode nested)
return true;
}
bool JsCode::parseIf(const char*& expr, Opcode nested)
class ParseWhile : public ParseNested
{
friend class JsCode;
public:
inline ParseWhile(JsCode* code, GenObject* nested, long int lblCont, long int lblBreak)
: ParseNested(code,nested,JsCode::OpcWhile),
m_lblCont(lblCont), m_lblBreak(lblBreak)
{ }
protected:
virtual bool isMatch(JsCode::JsOpcode opcode)
{ return JsCode::OpcBreak == opcode || JsCode::OpcCont == opcode; }
private:
long int m_lblCont;
long int m_lblBreak;
};
class ParseSwitch : public ParseNested
{
friend class JsCode;
public:
inline ParseSwitch(JsCode* code, GenObject* nested)
: ParseNested(code,nested,JsCode::OpcSwitch)
{ }
protected:
virtual bool isMatch(JsCode::JsOpcode opcode)
{ return JsCode::OpcCase == opcode || JsCode::OpcDefault == opcode ||
JsCode::OpcBreak == opcode; }
};
// Parse keywords inner to specific instructions
bool JsCode::parseInner(const char*& expr, JsOpcode opcode, ParseNested* nested)
{
switch (*nested) {
case OpcWhile:
switch (opcode) {
case OpcBreak:
addOpcode((Opcode)OpcJump,static_cast<ParseWhile*>(nested)->m_lblBreak);
break;
case OpcCont:
addOpcode((Opcode)OpcJump,static_cast<ParseWhile*>(nested)->m_lblCont);
break;
default:
return false;
}
break;
case OpcSwitch:
switch (opcode) {
case OpcCase:
if (!ExpEvaluator::getSimple(expr,true))
return gotError("Expecting case constant",expr);
break;
case OpcDefault:
break;
case OpcBreak:
break;
default:
return false;
}
break;
default:
return false;
}
return true;
}
bool JsCode::parseIf(const char*& expr, GenObject* nested)
{
if (skipComments(expr) != '(')
return gotError("Expecting '('",expr);
@ -906,7 +1001,7 @@ bool JsCode::parseIf(const char*& expr, Opcode nested)
return true;
}
bool JsCode::parseSwitch(const char*& expr, Opcode nested)
bool JsCode::parseSwitch(const char*& expr, GenObject* nested)
{
if (skipComments(expr) != '(')
return gotError("Expecting '('",expr);
@ -917,8 +1012,9 @@ bool JsCode::parseSwitch(const char*& expr, Opcode nested)
if (skipComments(++expr) != '{')
return gotError("Expecting '{'",expr);
expr++;
ParseSwitch parseStack(this,nested);
for (;;) {
if (!runCompile(expr,'}',(Opcode)OpcSwitch))
if (!runCompile(expr,'}',parseStack))
return false;
bool sep = false;
while (skipComments(expr) && getSeparator(expr,true))
@ -932,7 +1028,7 @@ bool JsCode::parseSwitch(const char*& expr, Opcode nested)
return true;
}
bool JsCode::parseFor(const char*& expr, Opcode nested)
bool JsCode::parseFor(const char*& expr, GenObject* nested)
{
if (skipComments(expr) != '(')
return gotError("Expecting '('",expr);
@ -940,14 +1036,15 @@ bool JsCode::parseFor(const char*& expr, Opcode nested)
return false;
if (skipComments(expr) != ')')
return gotError("Expecting ')'",expr);
if (!runCompile(++expr,';',(Opcode)OpcFor))
ParseNested parseStack(this,nested,OpcFor);
if (!runCompile(++expr,';',parseStack))
return false;
if (skipComments(expr) == ';')
expr++;
return true;
}
bool JsCode::parseWhile(const char*& expr, Opcode nested)
bool JsCode::parseWhile(const char*& expr, GenObject* nested)
{
ExpOperation* lbl = addOpcode(OpcLabel,++m_label);
if (skipComments(expr) != '(')
@ -957,17 +1054,19 @@ bool JsCode::parseWhile(const char*& expr, Opcode nested)
if (skipComments(expr) != ')')
return gotError("Expecting ')'",expr);
ExpOperation* jump = addOpcode((Opcode)OpcJumpFalse,++m_label);
if (!runCompile(++expr,0,(Opcode)OpcWhile))
ParseWhile parseStack(this,nested,lbl->number(),jump->number());
if (!runCompile(++expr,0,parseStack))
return false;
addOpcode((Opcode)OpcJump,lbl->number());
addOpcode(OpcLabel,jump->number());
return true;
}
bool JsCode::parseTry(const char*& expr, Opcode nested)
bool JsCode::parseTry(const char*& expr, GenObject* nested)
{
addOpcode((Opcode)OpcTry);
if (!runCompile(expr,0,(Opcode)OpcTry))
ParseNested parseStack(this,nested,OpcTry);
if (!runCompile(expr,0,parseStack))
return false;
skipComments(expr);
if ((JsOpcode)ExpEvaluator::getOperator(expr,s_instr) == OpcCatch) {
@ -988,7 +1087,7 @@ bool JsCode::parseTry(const char*& expr, Opcode nested)
return true;
}
bool JsCode::parseFuncDef(const char*& expr, Opcode nested)
bool JsCode::parseFuncDef(const char*& expr, GenObject* nested)
{
skipComments(expr);
int len = getKeyword(expr);

View File

@ -496,10 +496,10 @@ protected:
* Runs the parser and compiler for one (sub)expression
* @param expr Pointer to text to parse, gets advanced
* @param stop Optional character expected after the expression
* @param nested The instruction within this expression is nested
* @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, char stop = 0, Opcode nested = OpcNone);
virtual bool runCompile(const char*& expr, char stop = 0, GenObject* nested = 0);
/**
* Skip over comments and whitespaces
@ -570,10 +570,10 @@ protected:
/**
* Get an instruction or block, advance parsing pointer past it
* @param expr Pointer to text to parse, gets advanced on success
* @param nested The instruction within this one is nested
* @param nested User defined object passed from nested parsing
* @return True if succeeded, must add the operands internally
*/
virtual bool getInstruction(const char*& expr, Opcode nested = OpcNone);
virtual bool getInstruction(const char*& expr, GenObject* nested = 0);
/**
* Get an operand, advance parsing pointer past it