From: hama Date: Fri, 25 Jul 2014 23:02:01 +0000 (+0200) Subject: dayly work X-Git-Url: https://gitweb.hamatoma.de/?a=commitdiff_plain;h=71a9c57a43fde2798262733f4b097b8054be5668;p=reqt dayly work --- diff --git a/rplexpr/rplastree.cpp b/rplexpr/rplastree.cpp index 9f25c5b..dffb1de 100644 --- a/rplexpr/rplastree.cpp +++ b/rplexpr/rplastree.cpp @@ -744,6 +744,35 @@ void RplASNamedValue::dump(FILE* fp, int indent) positionStr(buffer, sizeof buffer)); } +/** @class RplASIndexedValue rplastree.hpp "rplexpr/rplastree.hpp" + * + * @brief Implements an indexed values (member of a list) + * + * m_child: the parent: a list expression + * m_child2: the index expression + */ +RplASIndexedValue::RplASIndexedValue() : + RplASNode2(AST_INDEXED_VALUE) +{ +} + +/** + * @brief Writes the internals into a file. + * + * @param fp target file + * @param indent nesting level + */ +void RplASIndexedValue::dump(FILE* fp, int indent) +{ + DEFINE_TABS(indent); + char buffer[256]; + fprintf(fp, "%sindexedValue id: %d index: %d parent: %d %s\n", tabs, + m_id, m_child2->id(), m_child->id(), + positionStr(buffer, sizeof buffer)); + m_child2->dump(fp, indent + 1); + m_child->dump(fp, indent + 1); +} + /** @class RplVarDefinition rplastree.hpp "rplexpr/rplastree.hpp" * * @brief Implements variable definition for the Abstract Syntax Tree. @@ -1856,17 +1885,23 @@ void RplASTree::dump(const char* filename, int flags, const char* header) * * m_child: next statement
* m_child2: argument list
+ * m_child3: parent (variable, field ...) */ /** * @brief Constructor. + * + * @param name name of the method/function + * @param parent NULL: it is a function
+ * otherwise: the parent (variable, field ...) */ -RplASMethodCall::RplASMethodCall(const QString& name) : - RplASNode2(AST_METHOD_CALL), + +RplASMethodCall::RplASMethodCall(const QString& name, RplASItem* parent) : + RplASNode3(AST_METHOD_CALL), RplASStatement(), m_name(name), m_method(NULL) { - + m_child3 = parent; } @@ -1880,13 +1915,16 @@ void RplASMethodCall::dump(FILE* fp, int indent) { DEFINE_TABS(indent); char buffer[256]; - fprintf(fp, "%scall %s Id: %d args: %d succ: %d %s\n", tabs, + fprintf(fp, "%scall %s Id: %d args: %d parent: %d succ: %d %s\n", tabs, m_name.toUtf8().constData(), m_id, m_child2 == NULL ? 0 : m_child2->id(), + m_child3 == NULL ? 0 : m_child3->id(), m_child == NULL ? 0 : m_child->id(), positionStr(buffer, sizeof buffer)); if (m_child2 != NULL) m_child2->dump(fp, indent + 1); + if (m_child3 != NULL) + m_child3->dump(fp, indent + 1); } /** @@ -2070,9 +2108,9 @@ void RplASArgument::dump(FILE* fp, int indent) /** @class RplASField rplastree.hpp "rplexpr/rplastree.hpp" * - * @brief Implements an argument of a method for the Abstract Syntax Tree. + * @brief Implements an class field for the Abstract Syntax Tree. * - * m_child: parent (variable, field, method)
+ * m_child: parent (variable, field, method) */ /** @@ -2096,8 +2134,11 @@ void RplASField::dump(FILE* fp, int indent) { DEFINE_TABS(indent); char buffer[256]; - fprintf(fp, "%sfield %s id: %d expr: %d succ: %s\n", tabs, + fprintf(fp, "%sfield %s id: %d parent: %d succ: %s\n", tabs, m_name.toUtf8().constData(), m_id, - m_child->id(), positionStr(buffer, sizeof buffer)); + m_child == NULL ? 0 : m_child->id(), + positionStr(buffer, sizeof buffer)); m_child->dump(fp, indent + 1); } + + diff --git a/rplexpr/rplastree.hpp b/rplexpr/rplastree.hpp index 72c168f..59e2087 100644 --- a/rplexpr/rplastree.hpp +++ b/rplexpr/rplastree.hpp @@ -18,6 +18,7 @@ enum RplASItemType { AST_MAP_CONSTANT, AST_MAP_ENTRY, AST_NAMED_VALUE, + AST_INDEXED_VALUE, AST_FIELD, AST_VAR_DEFINITION, AST_EXPR_STATEMENT, @@ -306,6 +307,13 @@ protected: RplASClass* m_dataType; }; +class RplASIndexedValue : public RplASNode2 { +public: + RplASIndexedValue(); +public: + void dump(FILE* fp, int indent); +}; + class RplASStatement { public: @@ -424,10 +432,10 @@ protected: }; class RplASMethod; -class RplASMethodCall : public RplASNode2, public RplASStatement +class RplASMethodCall : public RplASNode3, public RplASStatement { public: - RplASMethodCall(const QString& name); + RplASMethodCall(const QString& name, RplASItem* parent); public: void dump(FILE* fp, int indent); virtual void execute(); diff --git a/rplexpr/rplmfparser.cpp b/rplexpr/rplmfparser.cpp index 91ad007..bbdfebb 100644 --- a/rplexpr/rplmfparser.cpp +++ b/rplexpr/rplmfparser.cpp @@ -12,7 +12,7 @@ enum MFLocations{ L_PARSE_OPERAND_RPARENTH = 2001, - L_PARSE_FREE1, + L_PARSE_OPERAND_RPARENTH_INFO, L_TERM_WRONG_STRING, L_TERM_WRONG_NUMBER, L_PARSE_OPERAND_WRONG = 2005, @@ -42,7 +42,10 @@ enum MFLocations{ L_PARSE_OPERAND_NOT_OPERAND = 2030, L_PARSE_BODY_NO_START, L_PARSE_OPERAND_NO_BRACKET, - L_PARSE_ARGS_NO_COMMA_OR_PARENT + L_PARSE_ARGS_NO_COMMA_OR_PARENT, + L_PARSE_OPERAND_NO_FIELD2, + L_PARSE_OPERAND_NO_BRACKET2 = 2035, + L_PARSE_OPERAND_NO_FIELD }; /** @class RplMFParser rpllexer.hpp "rplexpr/rplmfparser.hpp" @@ -467,6 +470,32 @@ RplASItem* RplMFParser::parseMap() return rc; } +/** + * @brief Builds a node of a variable or a field. + * + * @param name name of the variable/field + * @param position source position + * @param parent NULL: result is a variable + * + * @return a RplASNamedValue or a + * RplASNamedValue instance + */ +RplASItem* RplMFParser::buildVarOrField(const QString& name, + const RplSourcePosition* position, RplASItem* parent) +{ + RplASItem* rc = NULL; + if (parent == NULL){ + RplASNamedValue* var = new RplASNamedValue(name); + var->setPosition(position); + rc = var; + } else { + RplASField* field = new RplASField(name); + field->setPosition(position); + rc = field; + field->setChild(parent); + } + return rc; +} /** * @brief Parses an operand. * @@ -476,7 +505,7 @@ RplASItem* RplMFParser::parseMap() * @post the token behind the operand is read * @return the node with the operand */ -RplASItem* RplMFParser::parseOperand(int level) +RplASItem* RplMFParser::parseOperand(int level, RplASItem* parent) { RplToken* token = m_lexer.nextNonSpaceToken(); const RplSourcePosition* startPosition = m_lexer.currentPosition(); @@ -486,9 +515,23 @@ RplASItem* RplMFParser::parseOperand(int level) case TOKEN_OPERATOR: { Operator opId = (Operator) token->id(); + if (parent != NULL && opId != O_LBRACKET) + syntaxError(L_PARSE_OPERAND_NO_FIELD, + "field expected (behind a '.')"); if (opId == O_LBRACKET){ - rc = parseList(); - readNext = false; + if (parent == NULL){ + rc = parseList(); + readNext = false; + } else { + RplASIndexedValue* value = new RplASIndexedValue(); + value->setPosition(startPosition); + value->setChild(parent); + rc = value; + value->setChild2(parseExpr(level + 1)); + if (! m_lexer.currentToken()->isOperator(O_RBRACKET)) + syntaxError(L_PARSE_OPERAND_NO_BRACKET2, + "']' expected"); + } } else if (opId == O_LBRACE){ rc = parseMap(); readNext = false; @@ -499,8 +542,7 @@ RplASItem* RplMFParser::parseOperand(int level) char buffer[256]; // this call never comes back (exception!) syntaxError(L_PARSE_OPERAND_RPARENTH, - "')' expected. '(' is at %s", - startPosition->utf8(buffer, sizeof buffer)); + "')' expected", "(", startPosition); } } else if (IS_UNARY_OP(opId)){ RplASUnaryOp* op = new RplASUnaryOp(token->id(), AST_PRE_UNARY_OP); @@ -517,6 +559,9 @@ RplASItem* RplMFParser::parseOperand(int level) case TOKEN_NUMBER: case TOKEN_REAL: { + if (parent != NULL) + syntaxError(L_PARSE_OPERAND_NO_FIELD2, + "field expected (behind a '.')"); RplASConstant* constant = new RplASConstant(); constant->setPosition(m_lexer.currentPosition()); rc = constant; @@ -541,12 +586,11 @@ RplASItem* RplMFParser::parseOperand(int level) token = m_lexer.nextNonSpaceToken(); startPosition = m_lexer.currentPosition(); if (token->tokenType() != TOKEN_OPERATOR){ - RplASNamedValue* var = new RplASNamedValue(name); - rc = var; + rc = buildVarOrField(name, startPosition, parent); readNext = false; } else { if (token->id() == O_LPARENTH){ - RplASMethodCall* call = new RplASMethodCall(name); + RplASMethodCall* call = new RplASMethodCall(name, parent); call->setPosition(startPosition); rc = call; @@ -558,19 +602,17 @@ RplASItem* RplMFParser::parseOperand(int level) readNext = false; } } else { - RplASNamedValue* var = new RplASNamedValue(name); - var->setPosition(startPosition); - rc = var; + rc = buildVarOrField(name, startPosition, parent); if (token->id() == O_LBRACKET){ RplASItem* indexExpr = parseExpr(0); if (! m_lexer.currentToken()->isOperator(O_RBRACKET)) syntaxError(L_PARSE_OPERAND_NO_BRACKET, "']' expected"); - var->setChild(indexExpr); + dynamic_cast(rc)->setChild(indexExpr); } else { if (token->id() == O_INC || token->id() == O_DEC){ RplASUnaryOp* op = new RplASUnaryOp(token->id(), AST_POST_UNARY_OP); - op->setChild(var); + op->setChild(rc); rc = op; } else { readNext = false; @@ -591,8 +633,11 @@ RplASItem* RplMFParser::parseOperand(int level) } if (readNext) m_lexer.nextNonSpaceToken(); -// if (m_lexer.currentToken()->isOperator(O_DOT)) - + if (m_lexer.currentToken()->isOperator(O_DOT, O_LBRACKET)){ + if (m_lexer.currentToken()->asInteger() == O_LBRACKET) + m_lexer.undoLastToken(); + rc = parseOperand(level, rc); + } return rc; } diff --git a/rplexpr/rplmfparser.hpp b/rplexpr/rplmfparser.hpp index e0637fa..3d581b2 100644 --- a/rplexpr/rplmfparser.hpp +++ b/rplexpr/rplmfparser.hpp @@ -87,10 +87,13 @@ public: RplASItem*parseMap(); protected: RplASArgument* parseArguments(); - RplASItem* parseOperand(int level); + RplASItem* parseOperand(int level, RplASItem* parent = NULL); RplASVariant* tokenToVariant(RplToken* token, bool endsWithComma, RplASNode1* parent); RplASVariant*createFormula(RplASNode1* parent); + RplASItem* buildVarOrField(const QString& name, + const RplSourcePosition* position, + RplASItem* parent); private: ///syntax token builder. /// Note: the super class contains a reference with the same name diff --git a/rplexpr/rplparser.cpp b/rplexpr/rplparser.cpp index a3290a6..c39570c 100644 --- a/rplexpr/rplparser.cpp +++ b/rplexpr/rplparser.cpp @@ -88,22 +88,44 @@ RplParser::RplParser(RplLexer& lexer, RplASTree& tree) : * * @param prefix first char in the message: 'E' (error) or 'W' (warning) * @param location unique id of the error/warning message + * @param position position of the error/warning * @param format message with placeholdes like sprintf() * @param varList the variable argument list */ -void RplParser::addMessage(char prefix, int location, const char* format, - va_list varList){ +void RplParser::addSimpleMessage(LevelTag prefix, int location, + const RplSourcePosition* position, + const char* message){ char buffer[2048]; QString msg; - const RplSourcePosition* pos = m_lexer.currentPosition(); snprintf(buffer, sizeof buffer, "%c%04d %s:%d-%d: ", prefix, location, - pos->sourceUnit()->name().toUtf8().constData(), - pos->lineNo(), pos->column()); - int length = strlen(buffer); - vsnprintf(buffer + length, -length + sizeof buffer, format, varList); + position->sourceUnit()->name().toUtf8().constData(), + position->lineNo(), position->column()); + int used = strlen(buffer); + int length = strlen(message); + if (length >= (int) sizeof buffer - used) + length = sizeof buffer - used - 1; + memcpy(buffer + used, message, length); + buffer[used + length] = '\0'; m_messages.append(buffer); } +/** + * @brief Common actions for the error/warning functions. + * + * @param prefix first char in the message: 'E' (error) or 'W' (warning) + * @param location unique id of the error/warning message + * @param position position of the error/warning + * @param format message with placeholdes like sprintf() + * @param varList the variable argument list + */ +void RplParser::addMessage(LevelTag prefix, int location, + const RplSourcePosition* position, + const char* format, va_list varList){ + char buffer[2048]; + vsnprintf(buffer, sizeof buffer, format, varList); + addSimpleMessage(prefix, location, position, buffer); +} + /** * @brief Adds an error message and throws an exception. * @@ -111,16 +133,42 @@ void RplParser::addMessage(char prefix, int location, const char* format, * * @param location unique id of the error/warning message * @param format message with placeholdes like sprintf() - * @param ... optional: the variable argument list */ -void RplParser::syntaxError(int location, const char* format, ...) +void RplParser::syntaxError(int location, const char* message) { - va_list ap; - va_start(ap, format); - addMessage('E', location, format, ap); - va_end(ap); - throw RplSyntaxError(format); + addSimpleMessage(LT_ERROR, location, m_lexer.currentPosition(), message); + throw RplSyntaxError(message); +} + +/** + * @brief Adds an error message and throws an exception. + * + * This method is used if a closing symbol (e.g. a ')' or 'end') is missed. + * The message contains a %s as an placeholder for the position of the + * starting symbol. + * The exception will be catched at a position where error recovery + * can take place. + * + * @param location unique id of the error + * @param message message describing the error + * @param symbol starting symbol corresponding to the missed closing symbol + * @param position position of the starting symbol + */ + +void RplParser::syntaxError(int location, const char* message, + const char* symbol, + const RplSourcePosition* position) +{ + char buffer[256]; + char buffer2[512]; + snprintf(buffer2, sizeof buffer2, + "The starting symbol %s is located here. Missing point: %s", + symbol, m_lexer.currentPosition()->utf8(buffer, sizeof buffer)); + + addSimpleMessage(LT_ERROR, location, m_lexer.currentPosition(), message); + addSimpleMessage(LT_INFO, location + 1, position, buffer2); + throw RplSyntaxError(message); } /** @@ -136,7 +184,7 @@ void RplParser::error(int location, const char* format, ...) { va_list ap; va_start(ap, format); - addMessage('E', location, format, ap); + addMessage(LT_ERROR, location, m_lexer.currentPosition(), format, ap); va_end(ap); if (++m_errors >= m_maxErrors) throw RplParserStop("too many errors"); @@ -155,7 +203,7 @@ void RplParser::warning(int location, const char* format, ...) { va_list ap; va_start(ap, format); - addMessage('W', location, format, ap); + addMessage(LT_WARNING, location, m_lexer.currentPosition(), format, ap); va_end(ap); if (++m_warnings >= m_maxWarnings) throw RplParserStop("too many warnings"); diff --git a/rplexpr/rplparser.hpp b/rplexpr/rplparser.hpp index e9334ac..5b40149 100644 --- a/rplexpr/rplparser.hpp +++ b/rplexpr/rplparser.hpp @@ -26,16 +26,29 @@ public: }; class RplParser { +public: + enum LevelTag { + LT_ERROR = 'E', + LT_WARNING = 'W', + LT_INFO = 'I' + }; + public: typedef QList MessageList; public: RplParser(RplLexer& lexer, RplASTree& ast); public: - void syntaxError(int location, const char* format, ...); + void addSimpleMessage(LevelTag prefix, int location, + const RplSourcePosition* pos, + const char* message); + void addMessage(LevelTag prefix, int location, + const RplSourcePosition* pos, + const char* format, va_list varList); + void syntaxError(int location, const char* message); + void syntaxError(int location, const char* message, const char* symbol, + const RplSourcePosition* position); void error(int location, const char* format, ...); void warning(int location, const char* format, ...); -protected: - void addMessage(char prefix, int location, const char* format, va_list varList); protected: RplLexer& m_lexer; diff --git a/test/rplmfparser/field1.txt b/test/rplmfparser/field1.txt new file mode 100644 index 0000000..b14cd76 --- /dev/null +++ b/test/rplmfparser/field1.txt @@ -0,0 +1,24 @@ +file.find('*.c')[0].name; +[1,2,3].join(' '); +3.14.trunc; += (module) parent: global +== Classes: +== Variables: +== Body: +Expr id: 8 expr: 7 succ: 15 :1:24 + field name id: 7 parent: 5 succ: :1:24 + indexedValue id: 5 index: 6 parent: 2 :1:16 + const id: 6 value: 0 :1:17 + call find Id: 2 args: 4 parent: 1 succ: 0 :1:9 + arg 1 id: 4 expr: 3 succ: 0 + const id: 3 value: '*.c' :1:10 + namedValue file id: 1 attr: 0x0 :1:4 +Expr id: 15 expr: 12 succ: 18 :2:12 + call join Id: 12 args: 14 parent: 9 succ: 0 :2:12 + arg 1 id: 14 expr: 13 succ: 0 + const id: 13 value: ' ' :2:13 + listConst id: 9 :1:26 + [1,2,] +Expr id: 18 expr: 17 succ: 0 :3:10 + field trunc id: 17 parent: 16 succ: :3:10 + const id: 16 value: 3.140000 :2:19 diff --git a/test/rplmfparser/forIt1.txt b/test/rplmfparser/forIt1.txt index 83e2e95..b32a016 100644 --- a/test/rplmfparser/forIt1.txt +++ b/test/rplmfparser/forIt1.txt @@ -10,7 +10,7 @@ varDef a id: 2 namedValue: 1 value: 0 succ: 4 :1:4 namedValue a id: 1 attr: 0x0 :1:4 forIt id: 4 var: 3 set: 5 body: 9 succ: 0 :1:7 namedValue x id: 3 attr: 0x0 :2:4 - namedValue a id: 5 attr: 0x0 + namedValue a id: 5 attr: 0x0 :2:11 Expr id: 9 expr: 7 succ: 0 :3:2 BinOp id: 7 op: += (6) left: 6 right: 8 :3:2 namedValue a id: 6 attr: 0x0 :3:2 diff --git a/test/rplmfparser/methc1.txt b/test/rplmfparser/methc1.txt index 0fe7a1f..bd9866a 100644 --- a/test/rplmfparser/methc1.txt +++ b/test/rplmfparser/methc1.txt @@ -6,20 +6,20 @@ max(1+2*3,4**(5-4)); == Variables: == Body: Expr id: 2 expr: 1 succ: 6 :1:4 - call rand Id: 1 args: 0 succ: 0 :1:4 + call rand Id: 1 args: 0 parent: 0 succ: 0 :1:4 Expr id: 6 expr: 3 succ: 20 :2:3 - call sin Id: 3 args: 5 succ: 0 :2:3 - Arg 1 id: 5 expr: 4 succ: 0 + call sin Id: 3 args: 5 parent: 0 succ: 0 :2:3 + arg 1 id: 5 expr: 4 succ: 0 namedValue a id: 4 attr: 0x0 :2:5 Expr id: 20 expr: 7 succ: 0 :3:3 - call max Id: 7 args: 13 succ: 0 :3:3 - Arg 1 id: 13 expr: 9 succ: 19 + call max Id: 7 args: 13 parent: 0 succ: 0 :3:3 + arg 1 id: 13 expr: 9 succ: 19 BinOp id: 9 op: + (26) left: 8 right: 11 :3:5 const id: 8 value: 1 :3:4 BinOp id: 11 op: * (30) left: 10 right: 12 :3:7 const id: 10 value: 2 :3:6 const id: 12 value: 3 :3:8 - Arg 2 id: 19 expr: 15 succ: 0 + arg 2 id: 19 expr: 15 succ: 0 BinOp id: 15 op: ** (31) left: 14 right: 17 :3:11 const id: 14 value: 4 :3:10 BinOp id: 17 op: - (27) left: 16 right: 18 :3:15 diff --git a/unittests/rplmfparser_test.cpp b/unittests/rplmfparser_test.cpp index 94d26f7..18abe4d 100644 --- a/unittests/rplmfparser_test.cpp +++ b/unittests/rplmfparser_test.cpp @@ -138,8 +138,16 @@ public: parser.parse(); checkAST("methc1.txt", __LINE__); } + void fieldTest(){ + //setSource("a.trunc;"); + setSource("file.find('*.c')[0].name;\n[1,2,3].join(' ');\n3.14.trunc;"); + RplMFParser parser(m_source, m_tree); + parser.parse(); + checkAST("field1.txt", __LINE__); + } virtual void doIt(void) { + fieldTest(); methodCallTest(); mapTest(); forItTest();