From 3147aebf7501cc1fc7c64d3b93832261c2eed47c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 10 Feb 2014 13:01:52 +0100 Subject: [PATCH] factored out declaration parser --- components/CMakeLists.txt | 2 +- components/compiler/declarationparser.cpp | 79 +++++++++++++++++++++++ components/compiler/declarationparser.hpp | 41 ++++++++++++ components/compiler/lineparser.cpp | 64 +++++++----------- components/compiler/lineparser.hpp | 1 - 5 files changed, 144 insertions(+), 43 deletions(-) create mode 100644 components/compiler/declarationparser.cpp create mode 100644 components/compiler/declarationparser.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index f2b16d4d5..4f6639e9b 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -55,7 +55,7 @@ add_component_dir (files add_component_dir (compiler context controlparser errorhandler exception exprparser extensions fileparser generator lineparser literals locals output parser scanner scriptparser skipparser streamerrorhandler - stringparser tokenloc nullerrorhandler opcodes extensions0 + stringparser tokenloc nullerrorhandler opcodes extensions0 declarationparser ) add_component_dir (interpreter diff --git a/components/compiler/declarationparser.cpp b/components/compiler/declarationparser.cpp new file mode 100644 index 000000000..586b28bc2 --- /dev/null +++ b/components/compiler/declarationparser.cpp @@ -0,0 +1,79 @@ + +#include "declarationparser.hpp" + +#include + +#include "scanner.hpp" +#include "errorhandler.hpp" +#include "skipparser.hpp" +#include "locals.hpp" + +Compiler::DeclarationParser::DeclarationParser (ErrorHandler& errorHandler, Context& context, + Locals& locals) +: Parser (errorHandler, context), mLocals (locals), mState (State_Begin), mType (0) +{} + +bool Compiler::DeclarationParser::parseName (const std::string& name, const TokenLoc& loc, + Scanner& scanner) +{ + if (mState==State_Name) + { + std::string name2 = Misc::StringUtils::lowerCase (name); + + char type = mLocals.getType (name2); + + if (type!=' ') + { + /// \todo add option to make re-declared local variables an error + getErrorHandler().warning ("can't re-declare local variable (ignoring declaration)", + loc); + SkipParser skip (getErrorHandler(), getContext()); + scanner.scan (skip); + mState = State_End; + return true; + } + + mLocals.declare (mType, name2); + + mState = State_End; + return true; + } + + return Parser::parseName (name, loc, scanner); +} + +bool Compiler::DeclarationParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) +{ + if (mState==State_Begin) + { + switch (keyword) + { + case Scanner::K_short: mType = 's'; break; + case Scanner::K_long: mType = 'l'; break; + case Scanner::K_float: mType = 'f'; break; + default: mType = 0; + } + + if (mType) + { + mState = State_Name; + return true; + } + } + else if (mState==State_Name) + { + // allow keywords to be used as local variable names. MW script compiler, you suck! + /// \todo option to disable this atrocity. + return parseName (loc.mLiteral, loc, scanner); + } + + return Parser::parseKeyword (keyword, loc, scanner); +} + +bool Compiler::DeclarationParser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner) +{ + if (code==Scanner::S_newline && mState==State_End) + return false; + + return Parser::parseSpecial (code, loc, scanner); +} \ No newline at end of file diff --git a/components/compiler/declarationparser.hpp b/components/compiler/declarationparser.hpp new file mode 100644 index 000000000..3e0ac57c3 --- /dev/null +++ b/components/compiler/declarationparser.hpp @@ -0,0 +1,41 @@ +#ifndef COMPILER_DECLARATIONPARSER_H_INCLUDED +#define COMPILER_DECLARATIONPARSER_H_INCLUDED + +#include "parser.hpp" + +namespace Compiler +{ + class Locals; + + class DeclarationParser : public Parser + { + enum State + { + State_Begin, State_Name, State_End + }; + + Locals& mLocals; + State mState; + char mType; + + public: + + DeclarationParser (ErrorHandler& errorHandler, Context& context, Locals& locals); + + virtual bool parseName (const std::string& name, const TokenLoc& loc, + Scanner& scanner); + ///< Handle a name token. + /// \return fetch another token? + + virtual bool parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner); + ///< Handle a keyword token. + /// \return fetch another token? + + virtual bool parseSpecial (int code, const TokenLoc& loc, Scanner& scanner); + ///< Handle a special character token. + /// \return fetch another token? + + }; +} + +#endif diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 2904df6e1..368152fd9 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -1,6 +1,8 @@ #include "lineparser.hpp" +#include + #include "scanner.hpp" #include "context.hpp" #include "errorhandler.hpp" @@ -8,7 +10,7 @@ #include "locals.hpp" #include "generator.hpp" #include "extensions.hpp" -#include +#include "declarationparser.hpp" namespace Compiler { @@ -82,37 +84,6 @@ namespace Compiler bool LineParser::parseName (const std::string& name, const TokenLoc& loc, Scanner& scanner) { - if (mState==ShortState || mState==LongState || mState==FloatState) - { - if (!getContext().canDeclareLocals()) - { - getErrorHandler().error ("local variables can't be declared in this context", loc); - SkipParser skip (getErrorHandler(), getContext()); - scanner.scan (skip); - return false; - } - - std::string name2 = Misc::StringUtils::lowerCase (name); - - char type = mLocals.getType (name2); - - if (type!=' ') - { - /// \todo add option to make re-declared local variables an error - getErrorHandler().warning ("can't re-declare local variable", loc); - SkipParser skip (getErrorHandler(), getContext()); - scanner.scan (skip); - mState = EndState; - return true; - } - - mLocals.declare (mState==ShortState ? 's' : (mState==LongState ? 'l' : 'f'), - name2); - - mState = EndState; - return true; - } - if (mState==SetState) { std::string name2 = Misc::StringUtils::lowerCase (name); @@ -303,9 +274,26 @@ namespace Compiler { switch (keyword) { - case Scanner::K_short: mState = ShortState; return true; - case Scanner::K_long: mState = LongState; return true; - case Scanner::K_float: mState = FloatState; return true; + case Scanner::K_short: + case Scanner::K_long: + case Scanner::K_float: + { + if (!getContext().canDeclareLocals()) + { + getErrorHandler().error ( + "local variables can't be declared in this context", loc); + SkipParser skip (getErrorHandler(), getContext()); + scanner.scan (skip); + return true; + } + + DeclarationParser declaration (getErrorHandler(), getContext(), mLocals); + if (declaration.parseKeyword (keyword, loc, scanner)) + scanner.scan (declaration); + + return true; + } + case Scanner::K_set: mState = SetState; return true; case Scanner::K_messagebox: mState = MessageState; return true; @@ -370,12 +358,6 @@ namespace Compiler mState = EndState; return true; } - else if (mState==ShortState || mState==LongState || mState==FloatState) - { - // allow keywords to be used as local variable names. MW script compiler, you suck! - /// \todo option to disable this atrocity. - return parseName (loc.mLiteral, loc, scanner); - } if (mAllowExpression) { diff --git a/components/compiler/lineparser.hpp b/components/compiler/lineparser.hpp index aa74cd232..cf72f26a8 100644 --- a/components/compiler/lineparser.hpp +++ b/components/compiler/lineparser.hpp @@ -20,7 +20,6 @@ namespace Compiler enum State { BeginState, - ShortState, LongState, FloatState, SetState, SetLocalVarState, SetGlobalVarState, SetPotentialMemberVarState, SetMemberVarState, SetMemberVarState2, MessageState, MessageCommaState, MessageButtonState, MessageButtonCommaState,