mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-29 10:56:37 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			292 lines
		
	
	
	
		
			8.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			292 lines
		
	
	
	
		
			8.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "controlparser.hpp"
 | |
| 
 | |
| #include <algorithm>
 | |
| #include <iterator>
 | |
| #include <stdexcept>
 | |
| 
 | |
| #include "errorhandler.hpp"
 | |
| #include "generator.hpp"
 | |
| #include "scanner.hpp"
 | |
| #include "skipparser.hpp"
 | |
| 
 | |
| namespace Compiler
 | |
| {
 | |
|     bool ControlParser::parseIfBody(int keyword, const TokenLoc& loc, Scanner& scanner)
 | |
|     {
 | |
|         if (keyword == Scanner::K_endif || keyword == Scanner::K_elseif || keyword == Scanner::K_else)
 | |
|         {
 | |
|             std::pair<Codes, Codes> entry;
 | |
| 
 | |
|             if (mState != IfElseBodyState)
 | |
|                 mExprParser.append(entry.first);
 | |
| 
 | |
|             std::copy(mCodeBlock.begin(), mCodeBlock.end(), std::back_inserter(entry.second));
 | |
| 
 | |
|             mIfCode.push_back(entry);
 | |
| 
 | |
|             mCodeBlock.clear();
 | |
| 
 | |
|             if (keyword == Scanner::K_endif)
 | |
|             {
 | |
|                 // store code for if-cascade
 | |
|                 Codes codes;
 | |
| 
 | |
|                 for (auto iter(mIfCode.rbegin()); iter != mIfCode.rend(); ++iter)
 | |
|                 {
 | |
|                     Codes block;
 | |
| 
 | |
|                     if (iter != mIfCode.rbegin())
 | |
|                         Generator::jump(iter->second, static_cast<int>(codes.size() + 1));
 | |
| 
 | |
|                     if (!iter->first.empty())
 | |
|                     {
 | |
|                         // if or elseif
 | |
|                         std::copy(iter->first.begin(), iter->first.end(), std::back_inserter(block));
 | |
|                         Generator::jumpOnZero(block, static_cast<int>(iter->second.size() + 1));
 | |
|                     }
 | |
| 
 | |
|                     std::copy(iter->second.begin(), iter->second.end(), std::back_inserter(block));
 | |
| 
 | |
|                     std::swap(codes, block);
 | |
| 
 | |
|                     std::copy(block.begin(), block.end(), std::back_inserter(codes));
 | |
|                 }
 | |
| 
 | |
|                 std::copy(codes.begin(), codes.end(), std::back_inserter(mCode));
 | |
| 
 | |
|                 mIfCode.clear();
 | |
|                 mState = IfEndifState;
 | |
|             }
 | |
|             else if (keyword == Scanner::K_elseif)
 | |
|             {
 | |
|                 mExprParser.reset();
 | |
|                 scanner.scan(mExprParser);
 | |
| 
 | |
|                 mState = IfElseifEndState;
 | |
|             }
 | |
|             else if (keyword == Scanner::K_else)
 | |
|             {
 | |
|                 mState = IfElseJunkState; /// \todo should be IfElseEndState; add an option for that
 | |
|             }
 | |
| 
 | |
|             return true;
 | |
|         }
 | |
|         else if (keyword == Scanner::K_if || keyword == Scanner::K_while)
 | |
|         {
 | |
|             // nested
 | |
|             ControlParser parser(getErrorHandler(), getContext(), mLocals, mLiterals);
 | |
| 
 | |
|             if (parser.parseKeyword(keyword, loc, scanner))
 | |
|                 scanner.scan(parser);
 | |
| 
 | |
|             parser.appendCode(mCodeBlock);
 | |
| 
 | |
|             return true;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             mLineParser.reset();
 | |
|             if (mLineParser.parseKeyword(keyword, loc, scanner))
 | |
|                 scanner.scan(mLineParser);
 | |
| 
 | |
|             return true;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     bool ControlParser::parseWhileBody(int keyword, const TokenLoc& loc, Scanner& scanner)
 | |
|     {
 | |
|         if (keyword == Scanner::K_endwhile)
 | |
|         {
 | |
|             Codes loop;
 | |
| 
 | |
|             Codes expr;
 | |
|             mExprParser.append(expr);
 | |
| 
 | |
|             Generator::jump(loop, -static_cast<int>(mCodeBlock.size() + expr.size()));
 | |
| 
 | |
|             std::copy(expr.begin(), expr.end(), std::back_inserter(mCode));
 | |
| 
 | |
|             Codes skip;
 | |
| 
 | |
|             Generator::jumpOnZero(skip, static_cast<int>(mCodeBlock.size() + loop.size() + 1));
 | |
| 
 | |
|             std::copy(skip.begin(), skip.end(), std::back_inserter(mCode));
 | |
| 
 | |
|             std::copy(mCodeBlock.begin(), mCodeBlock.end(), std::back_inserter(mCode));
 | |
| 
 | |
|             Codes loop2;
 | |
| 
 | |
|             Generator::jump(loop2, -static_cast<int>(mCodeBlock.size() + expr.size() + skip.size()));
 | |
| 
 | |
|             if (loop.size() != loop2.size())
 | |
|                 throw std::logic_error("Internal compiler error: failed to generate a while loop");
 | |
| 
 | |
|             std::copy(loop2.begin(), loop2.end(), std::back_inserter(mCode));
 | |
| 
 | |
|             mState = WhileEndwhileState;
 | |
|             return true;
 | |
|         }
 | |
|         else if (keyword == Scanner::K_if || keyword == Scanner::K_while)
 | |
|         {
 | |
|             // nested
 | |
|             ControlParser parser(getErrorHandler(), getContext(), mLocals, mLiterals);
 | |
| 
 | |
|             if (parser.parseKeyword(keyword, loc, scanner))
 | |
|                 scanner.scan(parser);
 | |
| 
 | |
|             parser.appendCode(mCodeBlock);
 | |
| 
 | |
|             return true;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             mLineParser.reset();
 | |
|             if (mLineParser.parseKeyword(keyword, loc, scanner))
 | |
|                 scanner.scan(mLineParser);
 | |
| 
 | |
|             return true;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     ControlParser::ControlParser(ErrorHandler& errorHandler, const Context& context, Locals& locals, Literals& literals)
 | |
|         : Parser(errorHandler, context)
 | |
|         , mLocals(locals)
 | |
|         , mLiterals(literals)
 | |
|         , mLineParser(errorHandler, context, locals, literals, mCodeBlock)
 | |
|         , mExprParser(errorHandler, context, locals, literals)
 | |
|         , mState(StartState)
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     void ControlParser::appendCode(std::vector<Interpreter::Type_Code>& code) const
 | |
|     {
 | |
|         std::copy(mCode.begin(), mCode.end(), std::back_inserter(code));
 | |
|     }
 | |
| 
 | |
|     bool ControlParser::parseName(const std::string& name, const TokenLoc& loc, Scanner& scanner)
 | |
|     {
 | |
|         if (mState == IfBodyState || mState == IfElseifBodyState || mState == IfElseBodyState
 | |
|             || mState == WhileBodyState)
 | |
|         {
 | |
|             scanner.putbackName(name, loc);
 | |
|             mLineParser.reset();
 | |
|             scanner.scan(mLineParser);
 | |
|             return true;
 | |
|         }
 | |
|         else if (mState == IfElseJunkState)
 | |
|         {
 | |
|             getErrorHandler().warning("Extra text after else", loc);
 | |
|             SkipParser skip(getErrorHandler(), getContext());
 | |
|             scanner.scan(skip);
 | |
|             mState = IfElseBodyState;
 | |
|             return true;
 | |
|         }
 | |
| 
 | |
|         return Parser::parseName(name, loc, scanner);
 | |
|     }
 | |
| 
 | |
|     bool ControlParser::parseKeyword(int keyword, const TokenLoc& loc, Scanner& scanner)
 | |
|     {
 | |
|         if (mState == StartState)
 | |
|         {
 | |
|             if (keyword == Scanner::K_if || keyword == Scanner::K_elseif)
 | |
|             {
 | |
|                 if (keyword == Scanner::K_elseif)
 | |
|                     getErrorHandler().warning("elseif without matching if", loc);
 | |
| 
 | |
|                 mExprParser.reset();
 | |
|                 scanner.scan(mExprParser);
 | |
| 
 | |
|                 mState = IfEndState;
 | |
|                 return true;
 | |
|             }
 | |
|             else if (keyword == Scanner::K_while)
 | |
|             {
 | |
|                 mExprParser.reset();
 | |
|                 scanner.scan(mExprParser);
 | |
| 
 | |
|                 mState = WhileEndState;
 | |
|                 return true;
 | |
|             }
 | |
|         }
 | |
|         else if (mState == IfBodyState || mState == IfElseifBodyState || mState == IfElseBodyState)
 | |
|         {
 | |
|             if (parseIfBody(keyword, loc, scanner))
 | |
|                 return true;
 | |
|         }
 | |
|         else if (mState == WhileBodyState)
 | |
|         {
 | |
|             if (parseWhileBody(keyword, loc, scanner))
 | |
|                 return true;
 | |
|         }
 | |
|         else if (mState == IfElseJunkState)
 | |
|         {
 | |
|             getErrorHandler().warning("Extra text after else", loc);
 | |
|             SkipParser skip(getErrorHandler(), getContext());
 | |
|             scanner.scan(skip);
 | |
|             mState = IfElseBodyState;
 | |
|             return true;
 | |
|         }
 | |
| 
 | |
|         return Parser::parseKeyword(keyword, loc, scanner);
 | |
|     }
 | |
| 
 | |
|     bool ControlParser::parseSpecial(int code, const TokenLoc& loc, Scanner& scanner)
 | |
|     {
 | |
|         if (code == Scanner::S_newline)
 | |
|         {
 | |
|             switch (mState)
 | |
|             {
 | |
|                 case IfEndState:
 | |
|                     mState = IfBodyState;
 | |
|                     return true;
 | |
|                 case IfElseifEndState:
 | |
|                     mState = IfElseifBodyState;
 | |
|                     return true;
 | |
|                 case IfElseEndState:
 | |
|                     mState = IfElseBodyState;
 | |
|                     return true;
 | |
|                 case IfElseJunkState:
 | |
|                     mState = IfElseBodyState;
 | |
|                     return true;
 | |
| 
 | |
|                 case WhileEndState:
 | |
|                     mState = WhileBodyState;
 | |
|                     return true;
 | |
| 
 | |
|                 case IfBodyState:
 | |
|                 case IfElseifBodyState:
 | |
|                 case IfElseBodyState:
 | |
|                 case WhileBodyState:
 | |
| 
 | |
|                     return true; // empty line
 | |
| 
 | |
|                 case IfEndifState:
 | |
|                 case WhileEndwhileState:
 | |
| 
 | |
|                     return false;
 | |
| 
 | |
|                 default:;
 | |
|             }
 | |
|         }
 | |
|         else if (mState == IfElseJunkState)
 | |
|         {
 | |
|             getErrorHandler().warning("Extra text after else", loc);
 | |
|             SkipParser skip(getErrorHandler(), getContext());
 | |
|             scanner.scan(skip);
 | |
|             mState = IfElseBodyState;
 | |
|             return true;
 | |
|         }
 | |
| 
 | |
|         return Parser::parseSpecial(code, loc, scanner);
 | |
|     }
 | |
| 
 | |
|     void ControlParser::reset()
 | |
|     {
 | |
|         mCode.clear();
 | |
|         mCodeBlock.clear();
 | |
|         mIfCode.clear();
 | |
|         mState = StartState;
 | |
|         Parser::reset();
 | |
|     }
 | |
| }
 |