mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-27 00:56:39 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			260 lines
		
	
	
	
		
			7.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			260 lines
		
	
	
	
		
			7.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
 | |
| #include "controlparser.hpp"
 | |
| 
 | |
| #include <algorithm>
 | |
| #include <iterator>
 | |
| #include <stdexcept>
 | |
| 
 | |
| #include "scanner.hpp"
 | |
| #include "generator.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 (IfCodes::reverse_iterator iter (mIfCode.rbegin());
 | |
|                     iter!=mIfCode.rend(); ++iter)
 | |
|                 {
 | |
|                     Codes block;
 | |
| 
 | |
|                     if (iter!=mIfCode.rbegin())
 | |
|                         Generator::jump (iter->second, 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, 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 = IfElseEndState;
 | |
|             }
 | |
| 
 | |
|             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, 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, 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;
 | |
|         }
 | |
| 
 | |
|         return Parser::parseName (name, loc, scanner);
 | |
|     }
 | |
| 
 | |
|     bool ControlParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner)
 | |
|     {
 | |
|         if (mState==StartState)
 | |
|         {
 | |
|             if (keyword==Scanner::K_if)
 | |
|             {
 | |
|                 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;
 | |
|         }
 | |
| 
 | |
|         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 WhileEndState: mState = WhileBodyState; return true;
 | |
| 
 | |
|                 case IfBodyState:
 | |
|                 case IfElseifBodyState:
 | |
|                 case IfElseBodyState:
 | |
|                 case WhileBodyState:
 | |
| 
 | |
|                     return true; // empty line
 | |
| 
 | |
|                 case IfEndifState:
 | |
|                 case WhileEndwhileState:
 | |
| 
 | |
|                     return false;
 | |
| 
 | |
|                 default: ;
 | |
|             }
 | |
| 
 | |
|         }
 | |
| 
 | |
|         return Parser::parseSpecial (code, loc, scanner);
 | |
|     }
 | |
| 
 | |
|     void ControlParser::reset()
 | |
|     {
 | |
|         mCode.clear();
 | |
|         mCodeBlock.clear();
 | |
|         mIfCode.clear();
 | |
|         mState = StartState;
 | |
|         Parser::reset();
 | |
|     }
 | |
| }
 |