From fac8fb8fcb2fe71c57d0d155f2df334aa7b9aac4 Mon Sep 17 00:00:00 2001
From: Marc Zinnschlag <marc@zpages.de>
Date: Wed, 30 Jun 2010 12:04:26 +0200
Subject: [PATCH] added return and messagebox statements (messagebox does
 neither formating nor buttons yet)

---
 apps/mwinterpreter/context.cpp            |  8 ++++++
 apps/mwinterpreter/context.hpp            |  3 +++
 components/compiler/generator.cpp         | 26 +++++++++++++++++++
 components/compiler/generator.hpp         |  6 +++++
 components/compiler/lineparser.cpp        | 20 +++++++++++++++
 components/compiler/lineparser.hpp        |  1 +
 components/compiler/scanner.hpp           |  2 +-
 components/interpreter/context.hpp        |  5 +++-
 components/interpreter/controlopcodes.hpp | 20 +++++++++++++++
 components/interpreter/docs/vmformat.txt  | 10 ++++++--
 components/interpreter/installopcodes.cpp |  8 ++++++
 components/interpreter/miscopcodes.hpp    | 31 +++++++++++++++++++++++
 components/interpreter/runtime.cpp        | 16 ++++++++++++
 components/interpreter/runtime.hpp        |  5 +++-
 14 files changed, 156 insertions(+), 5 deletions(-)
 create mode 100644 components/interpreter/controlopcodes.hpp
 create mode 100644 components/interpreter/miscopcodes.hpp

diff --git a/apps/mwinterpreter/context.cpp b/apps/mwinterpreter/context.cpp
index 618abaf83a..09d70ff3e7 100644
--- a/apps/mwinterpreter/context.cpp
+++ b/apps/mwinterpreter/context.cpp
@@ -67,6 +67,14 @@ namespace SAInterpreter
         mFloats.at (index) = value;
     }    
     
+    void Context::messageBox (const std::string& message,
+        const std::vector<std::string>& buttons)
+    {
+        std::cout << "message box: " << message << std::endl;
+        for (std::size_t i=0; i<buttons.size(); ++i)
+            std::cout << "    button " << i << ": " << buttons[i] << std::endl;
+    }
+                    
     void Context::report()
     {
         std::size_t i = 0;
diff --git a/apps/mwinterpreter/context.hpp b/apps/mwinterpreter/context.hpp
index c3ab9bad79..0f7ce5cefc 100644
--- a/apps/mwinterpreter/context.hpp
+++ b/apps/mwinterpreter/context.hpp
@@ -35,6 +35,9 @@ namespace SAInterpreter
 
             virtual void setLocalFloat (int index, float value);    
             
+            virtual void messageBox (const std::string& message,
+                const std::vector<std::string>& buttons); 
+                            
             void report();
             ///< Write state to std::cout   
     };
diff --git a/components/compiler/generator.cpp b/components/compiler/generator.cpp
index e704ac7241..ddbae874a4 100644
--- a/components/compiler/generator.cpp
+++ b/components/compiler/generator.cpp
@@ -150,6 +150,16 @@ namespace
     {
         code.push_back (segment5 (19));
     }    
+
+    void opReturn (Compiler::Generator::CodeContainer& code)
+    {
+        code.push_back (segment5 (20));
+    }       
+    
+    void opMessageBox (Compiler::Generator::CodeContainer& code, int buttons)
+    {
+        code.push_back (segment3 (0, buttons));
+    }
 }
 
 namespace Compiler
@@ -321,6 +331,22 @@ namespace Compiler
         {
             opSquareRoot (code);
         }
+        
+        void exit (CodeContainer& code)
+        {
+            opReturn (code);
+        }        
+        
+        void message (CodeContainer& code, Literals& literals, const std::string& message,
+            int buttons)
+        {
+            assert (buttons==0);
+
+            int index = literals.addString (message);
+            
+            opPushInt (code, index);
+            opMessageBox (code, buttons);
+        }
     }
 }
 
diff --git a/components/compiler/generator.hpp b/components/compiler/generator.hpp
index 44b0fc4f2a..2dd81711e2 100644
--- a/components/compiler/generator.hpp
+++ b/components/compiler/generator.hpp
@@ -2,6 +2,7 @@
 #define COMPILER_GENERATOR_H_INCLUDED
 
 #include <vector>
+#include <string>
 
 #include <components/interpreter/types.hpp>
 
@@ -33,6 +34,11 @@ namespace Compiler
         void convert (CodeContainer& code, char fromType, char toType);
         
         void squareRoot (CodeContainer& code);
+
+        void exit (CodeContainer& code);        
+        
+        void message (CodeContainer& code, Literals& literals, const std::string& message,
+            int buttons);
     }
 }
 
diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp
index 92c9aad57f..09ecdb82a5 100644
--- a/components/compiler/lineparser.cpp
+++ b/components/compiler/lineparser.cpp
@@ -76,6 +76,13 @@ namespace Compiler
             return false;            
         }
         
+        if (mState==MessageState || mState==MessageCommaState)
+        {
+            Generator::message (mCode, mLiterals, name, 0);
+            mState = EndState;
+            return false;
+        }
+        
         return Parser::parseName (name, loc, scanner);
     }
 
@@ -89,6 +96,13 @@ namespace Compiler
                 case Scanner::K_long: mState = LongState; return true;
                 case Scanner::K_float: mState = FloatState; return true;
                 case Scanner::K_set: mState = SetState; return true;
+                case Scanner::K_messagebox: mState = MessageState; return true;
+                
+                case Scanner::K_return:
+                
+                    Generator::exit (mCode);
+                    mState = EndState;
+                    return true;
             }
         }
         else if (mState==SetLocalVarState && keyword==Scanner::K_to)
@@ -114,6 +128,12 @@ namespace Compiler
         if (code==Scanner::S_newline && mState==EndState)
             return false;
             
+        if (code==Scanner::S_comma && mState==MessageState)
+        {
+            mState = MessageCommaState;
+            return true;
+        }
+            
         return Parser::parseSpecial (code, loc, scanner);
     }
     
diff --git a/components/compiler/lineparser.hpp b/components/compiler/lineparser.hpp
index e9fae92b73..0af222d86b 100644
--- a/components/compiler/lineparser.hpp
+++ b/components/compiler/lineparser.hpp
@@ -22,6 +22,7 @@ namespace Compiler
                 BeginState,
                 ShortState, LongState, FloatState,
                 SetState, SetLocalVarState,
+                MessageState, MessageCommaState,
                 EndState
             };
 
diff --git a/components/compiler/scanner.hpp b/components/compiler/scanner.hpp
index 271639c977..044e023757 100644
--- a/components/compiler/scanner.hpp
+++ b/components/compiler/scanner.hpp
@@ -40,7 +40,7 @@ namespace Compiler
                 K_if, K_endif, K_else, K_elseif,
                 K_while, K_endwhile,
                 K_return,
-                K_messageBox,
+                K_messagebox,
                 K_set, K_to,
                 K_getsquareroot
             };
diff --git a/components/interpreter/context.hpp b/components/interpreter/context.hpp
index 582606c9c4..32bde722ec 100644
--- a/components/interpreter/context.hpp
+++ b/components/interpreter/context.hpp
@@ -19,7 +19,10 @@ namespace Interpreter
 
             virtual void setLocalLong (int index, int value) = 0;        
 
-            virtual void setLocalFloat (int index, float value) = 0;        
+            virtual void setLocalFloat (int index, float value) = 0;
+            
+            virtual void messageBox (const std::string& message,
+                const std::vector<std::string>& buttons) = 0; 
     };
 }
 
diff --git a/components/interpreter/controlopcodes.hpp b/components/interpreter/controlopcodes.hpp
new file mode 100644
index 0000000000..90584decb0
--- /dev/null
+++ b/components/interpreter/controlopcodes.hpp
@@ -0,0 +1,20 @@
+#ifndef INTERPRETER_CONTROLOPCODES_H_INCLUDED
+#define INTERPRETER_CONTROLOPCODES_H_INCLUDED
+
+#include "opcodes.hpp"
+#include "runtime.hpp"
+
+namespace Interpreter
+{
+    class OpReturn : public Opcode0
+    {
+        public:
+        
+            virtual void execute (Runtime& runtime)
+            {
+                runtime.setPC (-1);
+            }           
+    };
+}
+
+#endif
diff --git a/components/interpreter/docs/vmformat.txt b/components/interpreter/docs/vmformat.txt
index 748e6e3ee1..c5bc133f70 100644
--- a/components/interpreter/docs/vmformat.txt
+++ b/components/interpreter/docs/vmformat.txt
@@ -43,7 +43,12 @@ opcodes 0-511 unused
 opcodes 512-1023 reserved for extensions
 
 Segment 3:
-opcodes 0-511 unused
+op    0: show message box with message string literal index in stack[0];
+         buttons (if any) in stack[arg0]..stack[1];
+         additional arguments (if any) in stack[arg0+n]..stack[arg0+1];
+         n is determined according to the message string
+         all arguments are removed from stack
+opcodes 1-511 unused
 opcodes 512-1023 reserved for extensions
 
 Segment 4:
@@ -71,6 +76,7 @@ op  16: div (float) stack[1] by stack[0], pop twice, push result
 op  17: convert stack[1] from integer to float
 op  18: convert stack[1] from float to integer
 op  19: take square root of stack[0] (float)
-opcodes 20-33554431 unused
+op  20: return
+opcodes 21-33554431 unused
 opcodes 33554432-67108863 reserved for extensions
 
diff --git a/components/interpreter/installopcodes.cpp b/components/interpreter/installopcodes.cpp
index b96a0a1a53..5836967ed1 100644
--- a/components/interpreter/installopcodes.cpp
+++ b/components/interpreter/installopcodes.cpp
@@ -5,6 +5,8 @@
 #include "genericopcodes.hpp"
 #include "localopcodes.hpp"
 #include "mathopcodes.hpp"
+#include "controlopcodes.hpp"
+#include "miscopcodes.hpp"
 
 namespace Interpreter
 {
@@ -36,6 +38,12 @@ namespace Interpreter
         interpreter.installSegment5 (15, new OpDivInt<Type_Integer>);
         interpreter.installSegment5 (16, new OpDivInt<Type_Float>);
         interpreter.installSegment5 (19, new OpSquareRoot);        
+        
+        // control structures
+        interpreter.installSegment5 (20, new OpReturn);        
+        
+        // misc
+        interpreter.installSegment3 (0, new OpMessageBox);        
     }
 }
 
diff --git a/components/interpreter/miscopcodes.hpp b/components/interpreter/miscopcodes.hpp
new file mode 100644
index 0000000000..f376208740
--- /dev/null
+++ b/components/interpreter/miscopcodes.hpp
@@ -0,0 +1,31 @@
+#ifndef INTERPRETER_MISCOPCODES_H_INCLUDED
+#define INTERPRETER_MISCOPCODES_H_INCLUDED
+
+#include <stdexcept>
+#include <vector>
+#include <string>
+
+#include "opcodes.hpp"
+#include "runtime.hpp"
+
+namespace Interpreter
+{
+    class OpMessageBox : public Opcode1
+    {
+        public:
+        
+            virtual void execute (Runtime& runtime, unsigned int arg0)
+            {
+                if (arg0!=0)
+                    throw std::logic_error ("message box buttons not implemented yet");
+                    
+                int index = runtime[0];
+                runtime.pop();
+                std::vector<std::string> buttons;
+                runtime.getContext().messageBox (runtime.getStringLiteral (index), buttons);
+            }        
+    };
+}
+
+#endif
+
diff --git a/components/interpreter/runtime.cpp b/components/interpreter/runtime.cpp
index bde4d6b9f2..746be60d2a 100644
--- a/components/interpreter/runtime.cpp
+++ b/components/interpreter/runtime.cpp
@@ -3,6 +3,7 @@
 
 #include <stdexcept>
 #include <cassert>
+#include <cstring>
 
 namespace Interpreter
 {
@@ -30,6 +31,21 @@ namespace Interpreter
         
         return *reinterpret_cast<const float *> (&literalBlock[index]);
     }
+    
+    std::string Runtime::getStringLiteral (int index) const
+    {
+        assert (index>=0 && index<static_cast<int> (mCode[3]));
+    
+        const char *literalBlock =
+            reinterpret_cast<const char *> (mCode + 4 + mCode[0] + mCode[1] + mCode[2]);
+    
+        for (; index; --index)
+        {
+            literalBlock += std::strlen (literalBlock) + 1;
+        }
+    
+        return literalBlock;
+    }
                     
     void Runtime::configure (const Interpreter::Type_Code *code, int codeSize)
     {    
diff --git a/components/interpreter/runtime.hpp b/components/interpreter/runtime.hpp
index a683a0f0fa..73e90f68a0 100644
--- a/components/interpreter/runtime.hpp
+++ b/components/interpreter/runtime.hpp
@@ -2,6 +2,7 @@
 #define INTERPRETER_RUNTIME_H_INCLUDED
 
 #include <vector>
+#include <string>
 
 #include "types.hpp"
 
@@ -29,7 +30,9 @@ namespace Interpreter
             int getIntegerLiteral (int index) const;
         
             float getFloatLiteral (int index) const;
-                    
+              
+            std::string getStringLiteral (int index) const;
+                                
             void configure (const Type_Code *code, int codeSize);
             ///< \a context and \a code must exist as least until either configure, clear or
             /// the destructor is called. \a codeSize is given in 32-bit words.