From: hama Date: Sat, 28 Jun 2014 22:21:49 +0000 (+0200) Subject: day's work X-Git-Url: https://gitweb.hamatoma.de/?a=commitdiff_plain;h=3631eb8dd8adf5ec7738d74c7f1c2bc74b233ca7;p=reqt day's work --- diff --git a/rplexpr/rplasclasses.cpp b/rplexpr/rplasclasses.cpp index ab2ffa1..4d08180 100644 --- a/rplexpr/rplasclasses.cpp +++ b/rplexpr/rplasclasses.cpp @@ -81,6 +81,18 @@ RplSymbolSpace::~RplSymbolSpace() delete it.value(); } } + +/** + * @brief Search the class in the symbol space hierarchy. + * + * @param name Name of the class + * @return NULL: not found
+ * otherwise: the class + */ +RplASClass*RplSymbolSpace::findClass(const QString& name) const +{ + return NULL; +} /** * @brief Returns the name of the symbol space. * diff --git a/rplexpr/rplastree.cpp b/rplexpr/rplastree.cpp index 0280713..c17a38c 100644 --- a/rplexpr/rplastree.cpp +++ b/rplexpr/rplastree.cpp @@ -20,6 +20,25 @@ unsigned int RplASItem::m_nextId = 1; * @brief RplASException::RplASException * @param message */ + + +/** + * @brief Builds the message. + * + * @param position describes the position of the error/warning + * @param format the reason of the exception + * @param varList the values for the placeholders in the format. + */ +void RplASException::build(const RplSourcePosition* position, + const char* format, va_list varList) +{ + char buffer[64000]; + if (position != NULL) + m_message = position->toString().toUtf8(); + vsnprintf(buffer, sizeof buffer, format, varList); + m_message += buffer; +} + /** * @brief Constructor. * @@ -31,16 +50,23 @@ RplASException::RplASException(const RplSourcePosition* position, const char* format, ...) : RplException("") { - char buffer[64000]; - if (position != NULL) - m_message = position->toString().toUtf8(); va_list ap; va_start(ap, format); - vsnprintf(buffer, sizeof buffer, format, ap); + build(position, format, ap); va_end(ap); - m_message += buffer; } +/** + * @brief Builds the message. + * + * @param position describes the position of the error/warning + * @param format the reason of the exception + * @param varList the values for the placeholders in the format. + */ +RplASException::RplASException() : + RplException("") +{ +} /** @class RplASVariant rplastree.hpp "rplexpr/rplastree.hpp" * @@ -283,7 +309,7 @@ QString RplASVariant::toString(int maxLength) const rc.sprintf("%f", m_value.m_float); break; case DT_INTEGER: - rc.sprintf("%d", m_value.m_float); + rc.sprintf("%d", m_value.m_int); break; case DT_OBJECT: m_class->toString(m_value.m_object, maxLength); @@ -502,6 +528,16 @@ RplASNode2::~RplASNode2() delete m_child2; m_child2 = NULL; } +RplASItem* RplASNode2::child2() const +{ + return m_child2; +} + +void RplASNode2::setChild2(RplASItem* child2) +{ + m_child2 = child2; +} + /** @class RplASNode3 rplastree.hpp "rplexpr/rplastree.hpp" * @@ -886,11 +922,25 @@ RplSymbolSpace* RplASTree::currentSpace() const } /** - * @brief Returns the method. - * - * @return the method + * @brief Constructor. */ -RplASMethod* RplAsMethodCall::method() const +RplASMethodCall::RplASMethodCall() : + RplASNode2(AST_METHOD_CALL), + RplASStatement() +{ + +} + +RplASMethodCall::~RplASMethodCall() +{ + +} + +void RplASMethodCall::execute() +{ +} + +RplASMethod* RplASMethodCall::method() const { return m_method; } @@ -899,7 +949,7 @@ RplASMethod* RplAsMethodCall::method() const * @brief Sets the method. * @param method method to set */ -void RplAsMethodCall::setMethod(RplASMethod* method) +void RplASMethodCall::setMethod(RplASMethod* method) { m_method = method; } @@ -909,7 +959,7 @@ void RplAsMethodCall::setMethod(RplASMethod* method) * * @return the first element of an argument list */ -RplArgument* RplAsMethodCall::arg1() const +RplASArgument* RplASMethodCall::arg1() const { return m_arg1; } @@ -919,8 +969,24 @@ RplArgument* RplAsMethodCall::arg1() const * * @param arg1 NULL or the first element of the argument list */ -void RplAsMethodCall::setArg1(RplArgument* arg1) +void RplASMethodCall::setArg1(RplASArgument* arg1) { m_arg1 = arg1; } + +RplASBinaryOp::RplASBinaryOp() : + RplASNode2(AST_BINARY_OP), + m_operator(0) +{ +} + +int RplASBinaryOp::getOperator() const +{ + return m_operator; +} + +void RplASBinaryOp::setOperator(int op) +{ + m_operator = op; +} diff --git a/rplexpr/rplastree.hpp b/rplexpr/rplastree.hpp index 76ef53b..f31fab1 100644 --- a/rplexpr/rplastree.hpp +++ b/rplexpr/rplastree.hpp @@ -32,7 +32,10 @@ enum RplASItemType { class RplASException : public RplException { public: + RplASException(); RplASException(const RplSourcePosition* position, const char* message, ...); +protected: + void build(const RplSourcePosition* position, const char* format, va_list varList); }; class RplASClass; @@ -179,6 +182,10 @@ class RplASNode2 : public RplASNode1 public: RplASNode2(RplASItemType type); virtual ~RplASNode2(); +public: + RplASItem* child2() const; + void setChild2(RplASItem* child2); + protected: RplASItem* m_child2; }; @@ -215,6 +222,10 @@ class RplASBinaryOp : public RplASNode2 { public: RplASBinaryOp(); +public: + int getOperator() const; + void setOperator(int op); + private: int m_operator; }; @@ -255,29 +266,32 @@ public: virtual ~RplASWhile(); }; -class RplArgument : public RplASNode2, public RplASStatement +class RplASArgument : public RplASNode2, public RplASStatement { public: - RplArgument(); - virtual ~RplArgument(); + RplASArgument(); + virtual ~RplASArgument(); }; class RplASMethod; -class RplAsMethodCall : public RplASNode2, public RplASStatement +class RplASMethodCall : public RplASNode2, public RplASStatement { public: - RplAsMethodCall(); - virtual ~RplAsMethodCall(); + RplASMethodCall(); + virtual ~RplASMethodCall(); +public: + virtual void execute(); + public: RplASMethod* method() const; void setMethod(RplASMethod* method); - RplArgument* arg1() const; - void setArg1(RplArgument* arg1); + RplASArgument* arg1() const; + void setArg1(RplASArgument* arg1); private: RplASMethod* m_method; - RplArgument* m_arg1; + RplASArgument* m_arg1; }; class RplParameter : RplASItem @@ -364,6 +378,7 @@ public: void finishClassOrMethod(const QString& name); SymbolSpaceStack& symbolSpaces(); RplSymbolSpace* currentSpace() const; + RplASClass* findClass(const QString& name); private: // the mother of all symbol spaces. diff --git a/rplexpr/rplexpr.hpp b/rplexpr/rplexpr.hpp index 18a9cf6..7b04db0 100644 --- a/rplexpr/rplexpr.hpp +++ b/rplexpr/rplexpr.hpp @@ -22,6 +22,7 @@ #include "rplexpr/rpllexer.hpp" #include "rplexpr/rplastree.hpp" #include "rplexpr/rplvm.hpp" +#include "rplexpr/rplparser.hpp" #include "rplexpr/rplmfparser.hpp" #endif // RPLEXPR_HPP diff --git a/rplexpr/rpllexer.cpp b/rplexpr/rpllexer.cpp index d7ad9a2..c74795f 100644 --- a/rplexpr/rpllexer.cpp +++ b/rplexpr/rpllexer.cpp @@ -745,6 +745,15 @@ void RplLexer::scanComment() m_input.remove(0, length); m_currentCol += length; } +/** + * @brief Returns the current position. + * + * @return the current source code position + */ +RplSourcePosition* RplLexer::currentPosition() const +{ + return m_currentPosition; +} /** * @brief Returns the next token. diff --git a/rplexpr/rpllexer.hpp b/rplexpr/rpllexer.hpp index 49a11e6..f761aff 100644 --- a/rplexpr/rpllexer.hpp +++ b/rplexpr/rpllexer.hpp @@ -171,6 +171,8 @@ public: void startUnit(const QString& unit); RplSource* source(); int prioOfOp(int op) const; + RplSourcePosition* currentPosition() const; + private: void prepareOperators(const char* operators); void initializeComments(const char* comments); diff --git a/rplexpr/rplmfparser.cpp b/rplexpr/rplmfparser.cpp index 69b56ed..78b5992 100644 --- a/rplexpr/rplmfparser.cpp +++ b/rplexpr/rplmfparser.cpp @@ -10,6 +10,13 @@ #include "rplcore/rplcore.hpp" #include "rplexpr/rplexpr.hpp" +enum MFLocations{ + L_PARSE_OPERAND_RPARENTH = 2000, + L_PARSE_OPERAND_RPARENTH_FUNC, + L_PARSE_OPERAND_WRONG + +}; + /** @class RplMFParser rpllexer.hpp "rplexpr/rplmfparser.hpp" * * @brief Implements a parser for the language MF. @@ -20,52 +27,57 @@ */ RplMFParser::RplMFParser(RplSource& source, RplASTree& abstractSyntaxTree) : + RplParser(m_lexer, abstractSyntaxTree), m_lexer(&source, MF_KEYWORDS, MF_OPERATORS, "/* */ // \n", "a-zA-Z_", "a-zA-Z0-9_", - RplLexer::NUMTYPE_ALL, RplLexer::SF_LIKE_C), - m_tree(abstractSyntaxTree) + RplLexer::NUMTYPE_ALL, RplLexer::SF_LIKE_C) { } /** * @brief Parses a function or a generator. */ -void RplMFParser::parseFunc() +RplASItem* RplMFParser::parseFunc() { - + RplASItem*rc = NULL; + return rc; } /** * @brief Parses an if statement. */ -void RplMFParser::parseIf() +RplASItem* RplMFParser::parseIf() { - + RplASItem*rc = NULL; + return rc; } /** * @brief Parses a while statement. */ -void RplMFParser::parseWhile() +RplASItem* RplMFParser::parseWhile() { - + RplASItem*rc = NULL; + return rc; } /** * @brief Parses a repeat statement. */ -void RplMFParser::parseRepeat() +RplASItem* RplMFParser::parseRepeat() { - + RplASItem*rc = NULL; + return rc; } /** * @brief Parses a for statement. */ -void RplMFParser::parseFor() +RplASItem* RplMFParser::parseFor() { - + RplASItem*rc = NULL; + return rc; } /** @@ -74,9 +86,10 @@ void RplMFParser::parseFor() * @param clazz NULL or the type of the variable * @param attribute 0 or attribute of the variable: K_CONST or K_LAZY */ -void RplMFParser::parseDefinition(RplASClass* clazz, Keyword attribute) +RplASItem* RplMFParser::parseDefinition(RplASClass* clazz, Keyword attribute) { - + RplASItem*rc = NULL; + return rc; } /** @@ -89,27 +102,43 @@ void RplMFParser::parseDefinition(RplASClass* clazz, Keyword attribute) RplASItem* RplMFParser::parseOperand(int level) { RplToken* token = m_lexer.nextNonSpaceToken(); + RplSourcePosition* startPosition = m_lexer.currentPosition(); RplASItem* rc = NULL; switch(token->tokenType()){ case TOKEN_OPERATOR: - rc = new RplASUnary(token->id()); - rc->setChild(parseOperand); + { + Operator op = (Operator) token->id(); + if (op == O_LPARENTH){ + rc = parseTerm(level + 1); + } else if (IS_UNARY_OP(op)){ + RplASUnaryOp* node = new RplASUnaryOp(token->id(), AST_PRE_UNARY_OP); + rc = node; + node->setChild(parseOperand(level)); + token = m_lexer.nextNonSpaceToken(); + if(token->tokenType() != TOKEN_OPERATOR || token->id() != O_RPARENT){ + QByteArray pos = startPosition->toString().toUtf8(); + // this call never comes back (exception!) + syntaxError(L_PARSE_OPERAND_RPARENTH, + "')' expected. '(' is at %s", pos.constData()); + } + } break; + } case TOKEN_STRING: case TOKEN_NUMBER: case TOKEN_REAL: { - RplASConstant constant = new RplASConstant(); - item = constant; + RplASConstant* constant = new RplASConstant(); + rc = constant; switch(token->tokenType()){ case TOKEN_STRING: - constant.m_value.setString(token->toString()); + constant->value().setString(token->toString()); break; case TOKEN_NUMBER: - constant.m_value.setInt(token->asInteger()); + constant->value().setInt(token->asInteger()); break; case TOKEN_REAL: - constant.m_value.setFloat(token->asReal()); + constant->value().setFloat(token->asReal()); break; default: break; @@ -120,26 +149,41 @@ RplASItem* RplMFParser::parseOperand(int level) { QString name = token->toString(); token = m_lexer.nextNonSpaceToken(); + startPosition = m_lexer.currentPosition(); if (token->tokenType() != TOKEN_OPERATOR){ RplASNamedValue* var = new RplASNamedValue(name); - item = var; + rc = var; m_lexer.undoLastToken(); } else { if (token->id() == O_LPARENTH){ - RplASItem* args = parseArguments(); - RplAsMethodCall node = new RplAsMethodCall(); - node.setArg1(args); + RplASArgument* args = parseArguments(); + RplASMethodCall* call = new RplASMethodCall(); + rc = call; + call->setArg1(args); + token = m_lexer.nextNonSpaceToken(); + if (token->tokenType() != TOKEN_OPERATOR + || token->id() != O_RPARENT){ + QByteArray pos = startPosition->toString().toUtf8(); + // this call never comes back (exception!) + syntaxError(L_PARSE_OPERAND_RPARENTH_FUNC, + "')' expected. '(' is at %s", pos.constData()); + } + } else if (token->id() == O_LBRACKET){ + } else if (token->id() == O_INC || token->id() == O_DEC){ RplASNamedValue* var = new RplASNamedValue(name); - item = var; + rc = var; } } break; } default: + // this call never comes back (exception!) + syntaxError(L_PARSE_OPERAND_WRONG, + "unexpected symbol detected. Operand expected"); break; } - return item; + return rc; } /** @@ -155,13 +199,13 @@ RplASItem* RplMFParser::parseOperand(int level) */ RplASItem* RplMFParser::parseTerm(int depth){ RplToken* token; - RplSourcePosition* start = m_lexer.currentSourcePosition(); + RplSourcePosition* start = m_lexer.currentPosition(); RplASItem* top = NULL; RplASItem* item; int lastPrio = -1; bool again = true; do { - item = parseOperand(level); + item = parseOperand(depth); token = m_lexer.nextNonSpaceToken(); RplTokenType tokenType = token->tokenType(); switch(tokenType){ @@ -169,12 +213,12 @@ RplASItem* RplMFParser::parseTerm(int depth){ { if (IS_BINARY_OP(tokenType)){ RplASBinaryOp* op = new RplASBinaryOp(); - op->setOp(token->id()); + op->setOperator(token->id()); int prio = m_lexer.prioOfOp(token->id()); op->setChild(item); op->setPosition(m_lexer.currentPosition()); - op->setChild2(parseOperand(level)); - if + op->setChild2(parseOperand(depth)); + } break; } @@ -183,7 +227,6 @@ RplASItem* RplMFParser::parseTerm(int depth){ case TOKEN_REAL: break; case TOKEN_KEYWORD: - case TOKEN_OPERATOR: case TOKEN_ID: case TOKEN_END_OF_SOURCE: again = false; @@ -199,13 +242,14 @@ RplASItem* RplMFParser::parseTerm(int depth){ * @brief Parses an expression. * * @precond the nextNonSpaceToken() will return the first token of the expr. - * @postcond all tokens belonging to the expr are read + * @postcond all tokens belonging to the expr are read (not more!) * - * @return the token behind the expr + * @return the tree of the expression */ -RplToken* RplMFParser::parseExpr() +RplASItem* RplMFParser::parseExpr() { - RplASItem* item = parseTerm(0); + RplASItem* rc = parseTerm(0); + return rc; } /** @@ -213,54 +257,55 @@ RplToken* RplMFParser::parseExpr() * * A body is a module, a class region or a method body. */ -void RplMFParser::parseBody() +RplASItem* RplMFParser::parseBody() { - RplToken token = m_lexer.nextNonSpaceToken(); - switch(token.tokenType()) + RplToken* token = m_lexer.nextNonSpaceToken(); + RplASItem* item = NULL; + switch(token->tokenType()) { case TOKEN_STRING: case TOKEN_NUMBER: case TOKEN_REAL: case TOKEN_OPERATOR: - m_lexer.undoNextToken(); - token = parseExpr(); + m_lexer.undoLastToken(); + item = parseExpr(); break; case TOKEN_KEYWORD: - switch (token.id()){ + switch (token->id()){ case K_IF: - parseIf(); + item = parseIf(); break; case K_WHILE: - parseWhile(); + item = parseWhile(); break; case K_REPEAT: - parseRepeat(); + item = parseRepeat(); break; case K_FOR: - parseFor(); + item = parseFor(); break; case K_CLASS: - parseClass(); + item = parseClass(); break; case K_FUNCTION: case K_GENERATOR: - parseMethod(); + item = parseMethodDefinition(); break; case K_IMPORT: parseImport(); break; case K_CONST: case K_LAZY: - parseDefinition(NULL, token.id()); + item = parseDefinition(NULL, (Keyword) token->id()); break; case K_INT: - parseDefinition(&RplASInteger.m_instance); + item = parseDefinition(&RplASInteger::m_instance, K_UNDEF); break; case K_FLOAT: - parseDefinition(&RplASFloat.m_instance); + parseDefinition(&RplASFloat::m_instance, K_UNDEF); break; case K_BOOL: - parseDefinition(&RplASBoolean.m_instance); + parseDefinition(&RplASBoolean::m_instance, K_UNDEF); break; default: break; @@ -268,12 +313,12 @@ void RplMFParser::parseBody() break; case TOKEN_ID: { - RplASClass* clazz = m_tree.currentSpace()->findClass(); + RplASClass* clazz = m_tree.currentSpace()->findClass(token->toString()); if (clazz != NULL){ - parseDefinition(clazz); + item = parseDefinition(clazz, K_UNDEF); } else { - m_lexer.undoNextToken(); - parseExpr(); + m_lexer.undoLastToken(); + item = parseExpr(); } break; } @@ -282,6 +327,36 @@ void RplMFParser::parseBody() default: break; } + //@ToDo: add item to list + return NULL; +} + +/** + * @brief Parses a class definition. + * @return the node in an abstract syntax tree + */ +RplASItem*RplMFParser::parseMethodDefinition() +{ + RplASItem* rc = NULL; + return rc; +} + +/** + * @brief Parses a class definition. + * @return the node in an abstract syntax tree + */ +RplASItem*RplMFParser::parseClass() +{ + RplASItem* rc = NULL; + return rc; +} + +/** + * @brief Parses a the import statement + */ +void RplMFParser::parseImport() +{ + } /** @@ -292,7 +367,7 @@ void RplMFParser::parseBody() * * @param name the name of the module (without path) */ -void RplMFParser::parseModule(const QString& name) +RplASItem* RplMFParser::parseModule(const QString& name) { m_tree.startModule(name); parseBody(); @@ -306,3 +381,12 @@ void RplMFParser::parse() } +/** + * @brief Parses an argument list. + * @return the first element of the argument list + */ +RplASArgument*RplMFParser::parseArguments() +{ + +} + diff --git a/rplexpr/rplmfparser.hpp b/rplexpr/rplmfparser.hpp index fbe938d..3e5770a 100644 --- a/rplexpr/rplmfparser.hpp +++ b/rplexpr/rplmfparser.hpp @@ -10,7 +10,7 @@ #ifndef RPLMFPARSER_HPP #define RPLMFPARSER_HPP -class RplMFParser +class RplMFParser : public RplParser { public: enum Keyword { @@ -64,22 +64,25 @@ public: public: RplMFParser(RplSource& source, RplASTree& ast); public: - void parseFunc(); - void parseIf(); - void parseWhile(); - void parseRepeat(); - void parseFor(); - void parseDefinition(RplASClass* clazz, Keyword attribute); - RplToken* parseExpr(); - void parseBody(); - void parseClass(); - void parseModule(const QString& name); + RplASItem* parseFunc(); + RplASItem* parseIf(); + RplASItem* parseWhile(); + RplASItem* parseRepeat(); + RplASItem* parseFor(); + RplASItem* parseDefinition(RplASClass* clazz, Keyword attribute); + RplASItem* parseExpr(); + RplASItem* parseBody(); + RplASItem* parseMethodDefinition(); + RplASItem* parseClass(); + void parseImport(); + RplASItem* parseModule(const QString& name); void parse(); +protected: + RplASArgument* parseArguments(); RplASItem* parseOperand(int level); RplASItem* parseTerm(int depth); private: RplLexer m_lexer; - RplASTree& m_tree; }; #endif // RPLMFPARSER_HPP diff --git a/rplexpr/rplparser.cpp b/rplexpr/rplparser.cpp new file mode 100644 index 0000000..ff68682 --- /dev/null +++ b/rplexpr/rplparser.cpp @@ -0,0 +1,155 @@ +/* + * Licence: + * You can use and modify this file without any restriction. + * There is no warranty. + * You also can use the licence from http://www.wtfpl.net/. + * The original sources can be found on https://github.com/republib. +*/ + +#include "rplcore/rplcore.hpp" +#include "rplexpr/rplexpr.hpp" + + +/** @class RplSyntaxError rplparser.hpp "rplexpr/rplparser.hpp" + * + * @brief Implements an exception used for jumping out from many nested calls. + * + * We don't want to cancel the parse process if an syntax error has been + * occurred. Therefore we want to recreate after it. + * A relative simple solution: + * Ignoring the rest of the statement and start again with the next statement. + * Often the detection is done deep in an expression and we must jump out. + * This allows this exception. + */ + +/** + * @brief Constructor. + * @param reason the reason of the exception + * @return + */ +RplSyntaxError::RplSyntaxError(const char* reason) : + m_reason(reason) +{ +} + +/** @class RplParserStop rplparser.hpp "rplexpr/rplparser.hpp" + * + * @brief Implements an exception used for jumping out from many nested calls. + * + * In some situation we want to abort the parsing process. + * This exception allows this without high costs even the abort position + * is in a deep nested call. + */ + +/** + * @brief Constructor. + * @param reason the reason of the exception + * @return + */ +RplParserStop::RplParserStop(const char* reason) : + RplSyntaxError(reason) +{ +} + +/** @class RplParser rplparser.hpp "rplexpr/rplparser.hpp" + * + * @brief Implements a base class for parsers. + * + * This class offers common things for all parsers, e.g. error handling. + */ +/** + * @brief Constructor. + * + * @param lexer the tokenizer + * @param tree the abstract syntax tree + */ +RplParser::RplParser(RplLexer& lexer, RplASTree& tree) : + m_lexer(lexer), + m_tree(tree), + m_messages(), + m_errors(0), + m_warnings(0), + m_maxErrors(20), + m_maxWarnings(20) +{ +} + +/** + * @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 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){ + char buffer[2048]; + QString msg; + 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); + m_messages.append(buffer); +} + +/** + * @brief Adds an error message and throws an exception. + * + * The exception will be catched at a position where error recovery can take place. + * + * @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, ...) +{ + va_list ap; + va_start(ap, format); + addMessage('E', location, format, ap); + va_end(ap); + throw RplSyntaxError(format); +} + +/** + * @brief Adds an error message. + * + * If too much errors an exception will be thrown to stop parsing. + * + * @param location unique id of the error/warning message + * @param format message with placeholdes like sprintf() + * @param ... optional: the variable argument list + */ +void RplParser::error(int location, const char* format, ...) +{ + va_list ap; + va_start(ap, format); + addMessage('E', location, format, ap); + va_end(ap); + if (++m_errors >= m_maxErrors) + throw RplParserStop("too many errors"); +} + +/** + * @brief Adds a warning message. + * + * If too much warnings an exception will be thrown to stop parsing. + * + * @param location unique id of the error/warning message + * @param format message with placeholdes like sprintf() + * @param ... optional: the variable argument list + */ +void RplParser::warning(int location, const char* format, ...) +{ + va_list ap; + va_start(ap, format); + addMessage('W', location, 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 new file mode 100644 index 0000000..333b2b0 --- /dev/null +++ b/rplexpr/rplparser.hpp @@ -0,0 +1,48 @@ +/* + * Licence: + * You can use and modify this file without any restriction. + * There is no warranty. + * You also can use the licence from http://www.wtfpl.net/. + * The original sources can be found on https://github.com/republib. +*/ + + +#ifndef RPLPARSER_HPP +#define RPLPARSER_HPP + +class RplSyntaxError +{ +public: + RplSyntaxError(const char* reason); +private: + const char* m_reason; +}; + +class RplParserStop : public RplSyntaxError { +public: + RplParserStop(const char* reason); +}; + +class RplParser { +public: + typedef QList MessageList; +public: + RplParser(RplLexer& lexer, RplASTree& ast); +public: + void syntaxError(int location, const char* format, ...); + 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; + RplASTree& m_tree; + MessageList m_messages; + int m_errors; + int m_warnings; + int m_maxErrors; + int m_maxWarnings; +}; + +#endif // RPLPARSER_HPP diff --git a/rplexpr/rplsource.cpp b/rplexpr/rplsource.cpp index 5e147ff..3b3b316 100644 --- a/rplexpr/rplsource.cpp +++ b/rplexpr/rplsource.cpp @@ -161,6 +161,15 @@ QString RplSourcePosition::toString() const return rc; } +/** + * @brief Returns the line number. + * @return the line number + */ +int RplSourcePosition::lineNo() const +{ + return m_lineNo; +} + /** * @brief Sets the line number. * diff --git a/rplstatic/rplstatic.pro b/rplstatic/rplstatic.pro index 78d1cd8..19d3f14 100644 --- a/rplstatic/rplstatic.pro +++ b/rplstatic/rplstatic.pro @@ -36,7 +36,8 @@ SOURCES += \ ../rplexpr/rplastree.cpp \ ../rplexpr/rplasclasses.cpp \ ../rplexpr/rplmfparser.cpp \ - ../rplexpr/rplvm.cpp + ../rplexpr/rplvm.cpp \ + ../rplexpr/rplparser.cpp HEADERS += ../rplmodules.hpp \ ../rplcore/rplconfig.hpp \ @@ -64,7 +65,8 @@ HEADERS += ../rplmodules.hpp \ ../rplexpr/rplastree.hpp \ ../rplexpr/rplasclasses.hpp \ ../rplexpr/rplmfparser.hpp \ - ../rplexpr/rplvm.hpp + ../rplexpr/rplvm.hpp \ + ../rplexpr/rplparser.hpp unix:!symbian { maemo5 { diff --git a/unittests/rplmfparser_test.cpp b/unittests/rplmfparser_test.cpp index 5a635d0..e5a188f 100644 --- a/unittests/rplmfparser_test.cpp +++ b/unittests/rplmfparser_test.cpp @@ -28,6 +28,7 @@ public: } virtual void doIt(void) { + baseTest(); } }; void testRplMFParser() { diff --git a/unittests/unittests.pro b/unittests/unittests.pro index 29e0bce..4ce578f 100644 --- a/unittests/unittests.pro +++ b/unittests/unittests.pro @@ -26,6 +26,7 @@ SOURCES += main.cpp \ ../rplexpr/rplsource.cpp \ ../rplexpr/rpllexer.cpp \ ../rplexpr/rplastree.cpp \ + ../rplexpr/rplparser.cpp \ ../rplexpr/rplmfparser.cpp \ rplexception_test.cpp \ rplstring_test.cpp \