forked from mirror/openmw-tes3mp
added parsing for set statement (only integer values so far); added code generator
This commit is contained in:
parent
5cf3264bd3
commit
fdcd34941b
9 changed files with 278 additions and 5 deletions
|
@ -72,7 +72,7 @@ set(COMPILER components/compiler/errorhandler.cpp
|
||||||
components/compiler/parser.cpp components/compiler/scanner.cpp
|
components/compiler/parser.cpp components/compiler/scanner.cpp
|
||||||
components/compiler/streamerrorhandler.cpp
|
components/compiler/streamerrorhandler.cpp
|
||||||
components/compiler/locals.cpp components/compiler/literals.cpp
|
components/compiler/locals.cpp components/compiler/literals.cpp
|
||||||
components/compiler/output.cpp)
|
components/compiler/output.cpp components/compiler/generator.cpp)
|
||||||
file(GLOB COMPILER_HEADER components/compiler/*.hpp)
|
file(GLOB COMPILER_HEADER components/compiler/*.hpp)
|
||||||
source_group(compiler FILES ${COMPILER} ${COMPILER_HEADER})
|
source_group(compiler FILES ${COMPILER} ${COMPILER_HEADER})
|
||||||
|
|
||||||
|
|
120
components/compiler/generator.cpp
Normal file
120
components/compiler/generator.cpp
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
|
||||||
|
#include "generator.hpp"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "literals.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
Interpreter::Type_Code segment0 (unsigned int c, unsigned int arg0)
|
||||||
|
{
|
||||||
|
assert (c<64);
|
||||||
|
return (c<<24) | (arg0 & 0xffffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
Interpreter::Type_Code segment1 (unsigned int c, unsigned int arg0, unsigned int arg1)
|
||||||
|
{
|
||||||
|
assert (c<64);
|
||||||
|
return 0x40000000 | (c<<24) | ((arg0 & 0xfff)<<12) | (arg1 & 0xfff);
|
||||||
|
}
|
||||||
|
|
||||||
|
Interpreter::Type_Code segment2 (unsigned int c, unsigned int arg0)
|
||||||
|
{
|
||||||
|
assert (c<1024);
|
||||||
|
return 0x80000000 | (c<<20) | (arg0 & 0xfffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
Interpreter::Type_Code segment3 (unsigned int c, unsigned int arg0)
|
||||||
|
{
|
||||||
|
assert (c<1024);
|
||||||
|
return 0xc0000000 | (c<<20) | (arg0 & 0xffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
Interpreter::Type_Code segment4 (unsigned int c, unsigned int arg0, unsigned int arg1)
|
||||||
|
{
|
||||||
|
assert (c<1024);
|
||||||
|
return 0xc4000000 | (c<<16) | ((arg0 & 0xff)<<8) | (arg1 & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
Interpreter::Type_Code segment5 (unsigned int c)
|
||||||
|
{
|
||||||
|
assert (c<67108864);
|
||||||
|
return 0xc8000000 | c;
|
||||||
|
}
|
||||||
|
|
||||||
|
void opPushInt (Compiler::Generator::CodeContainer& code, int value)
|
||||||
|
{
|
||||||
|
code.push_back (segment0 (0, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void opFetchIntLiteral (Compiler::Generator::CodeContainer& code)
|
||||||
|
{
|
||||||
|
code.push_back (segment5 (4));
|
||||||
|
}
|
||||||
|
|
||||||
|
void opFetchFloatLiteral (Compiler::Generator::CodeContainer& code)
|
||||||
|
{
|
||||||
|
code.push_back (segment5 (5));
|
||||||
|
}
|
||||||
|
|
||||||
|
void opIntToFloat (Compiler::Generator::CodeContainer& code)
|
||||||
|
{
|
||||||
|
code.push_back (segment5 (3));
|
||||||
|
}
|
||||||
|
|
||||||
|
void opStoreLocalShort (Compiler::Generator::CodeContainer& code)
|
||||||
|
{
|
||||||
|
code.push_back (segment5 (0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void opStoreLocalLong (Compiler::Generator::CodeContainer& code)
|
||||||
|
{
|
||||||
|
code.push_back (segment5 (1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void opStoreLocalFloat (Compiler::Generator::CodeContainer& code)
|
||||||
|
{
|
||||||
|
code.push_back (segment5 (2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Compiler
|
||||||
|
{
|
||||||
|
namespace Generator
|
||||||
|
{
|
||||||
|
void assignIntToLocal (CodeContainer& code, Literals& literals, char localType,
|
||||||
|
int localIndex, int value)
|
||||||
|
{
|
||||||
|
int index = literals.addInteger (value);
|
||||||
|
|
||||||
|
opPushInt (code, localIndex);
|
||||||
|
opPushInt (code, index);
|
||||||
|
opFetchIntLiteral (code);
|
||||||
|
|
||||||
|
switch (localType)
|
||||||
|
{
|
||||||
|
case 'f':
|
||||||
|
|
||||||
|
opIntToFloat (code);
|
||||||
|
opStoreLocalFloat (code);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
|
||||||
|
opStoreLocalShort (code);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'l':
|
||||||
|
|
||||||
|
opStoreLocalLong (code);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
assert (0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
22
components/compiler/generator.hpp
Normal file
22
components/compiler/generator.hpp
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef COMPILER_GENERATOR_H_INCLUDED
|
||||||
|
#define COMPILER_GENERATOR_H_INCLUDED
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <components/interpreter/types.hpp>
|
||||||
|
|
||||||
|
namespace Compiler
|
||||||
|
{
|
||||||
|
class Literals;
|
||||||
|
|
||||||
|
namespace Generator
|
||||||
|
{
|
||||||
|
typedef std::vector<Interpreter::Type_Code> CodeContainer;
|
||||||
|
|
||||||
|
void assignIntToLocal (CodeContainer& code, Literals& literals, char localType,
|
||||||
|
int localIndex, int value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "errorhandler.hpp"
|
#include "errorhandler.hpp"
|
||||||
#include "skipparser.hpp"
|
#include "skipparser.hpp"
|
||||||
#include "locals.hpp"
|
#include "locals.hpp"
|
||||||
|
#include "generator.hpp"
|
||||||
|
|
||||||
namespace Compiler
|
namespace Compiler
|
||||||
{
|
{
|
||||||
|
@ -17,6 +18,17 @@ namespace Compiler
|
||||||
|
|
||||||
bool LineParser::parseInt (int value, const TokenLoc& loc, Scanner& scanner)
|
bool LineParser::parseInt (int value, const TokenLoc& loc, Scanner& scanner)
|
||||||
{
|
{
|
||||||
|
if (mState==SetLocalToState)
|
||||||
|
{
|
||||||
|
Generator::assignIntToLocal (mCode, mLiterals, mLocals.getType (mName),
|
||||||
|
mLocals.getIndex (mName), value);
|
||||||
|
|
||||||
|
mState = EndState;
|
||||||
|
mName.clear();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return Parser::parseInt (value, loc, scanner);
|
return Parser::parseInt (value, loc, scanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,6 +67,23 @@ namespace Compiler
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mState==SetState)
|
||||||
|
{
|
||||||
|
// local variable?
|
||||||
|
char type = mLocals.getType (name);
|
||||||
|
if (type!=' ')
|
||||||
|
{
|
||||||
|
mName = name;
|
||||||
|
mState = SetLocalVarState;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
getErrorHandler().error ("unknown variable", loc);
|
||||||
|
SkipParser skip (getErrorHandler(), getContext());
|
||||||
|
scanner.scan (skip);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return Parser::parseName (name, loc, scanner);
|
return Parser::parseName (name, loc, scanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,8 +96,14 @@ namespace Compiler
|
||||||
case Scanner::K_short: mState = ShortState; return true;
|
case Scanner::K_short: mState = ShortState; return true;
|
||||||
case Scanner::K_long: mState = LongState; return true;
|
case Scanner::K_long: mState = LongState; return true;
|
||||||
case Scanner::K_float: mState = FloatState; return true;
|
case Scanner::K_float: mState = FloatState; return true;
|
||||||
|
case Scanner::K_set: mState = SetState; return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (mState==SetLocalVarState && keyword==Scanner::K_to)
|
||||||
|
{
|
||||||
|
mState = SetLocalToState;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return Parser::parseKeyword (keyword, loc, scanner);
|
return Parser::parseKeyword (keyword, loc, scanner);
|
||||||
}
|
}
|
||||||
|
@ -84,6 +119,7 @@ namespace Compiler
|
||||||
void LineParser::reset()
|
void LineParser::reset()
|
||||||
{
|
{
|
||||||
mState = BeginState;
|
mState = BeginState;
|
||||||
|
mName.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ namespace Compiler
|
||||||
{
|
{
|
||||||
BeginState,
|
BeginState,
|
||||||
ShortState, LongState, FloatState,
|
ShortState, LongState, FloatState,
|
||||||
|
SetState, SetLocalVarState, SetLocalToState,
|
||||||
EndState
|
EndState
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -27,6 +28,7 @@ namespace Compiler
|
||||||
Literals& mLiterals;
|
Literals& mLiterals;
|
||||||
std::vector<Interpreter::Type_Code>& mCode;
|
std::vector<Interpreter::Type_Code>& mCode;
|
||||||
State mState;
|
State mState;
|
||||||
|
std::string mName;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
|
@ -21,11 +21,22 @@ namespace Compiler
|
||||||
throw std::logic_error ("unknown variable type");
|
throw std::logic_error ("unknown variable type");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Locals::search (char type, const std::string& name) const
|
int Locals::searchIndex (char type, const std::string& name) const
|
||||||
{
|
{
|
||||||
const std::vector<std::string>& collection = get (type);
|
const std::vector<std::string>& collection = get (type);
|
||||||
|
|
||||||
return std::find (collection.begin(), collection.end(), name)!=collection.end();
|
std::vector<std::string>::const_iterator iter =
|
||||||
|
std::find (collection.begin(), collection.end(), name);
|
||||||
|
|
||||||
|
if (iter==collection.end())
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return iter-collection.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Locals::search (char type, const std::string& name) const
|
||||||
|
{
|
||||||
|
return searchIndex (type, name)!=-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string>& Locals::get (char type)
|
std::vector<std::string>& Locals::get (char type)
|
||||||
|
@ -54,6 +65,21 @@ namespace Compiler
|
||||||
return ' ';
|
return ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Locals::getIndex (const std::string& name) const
|
||||||
|
{
|
||||||
|
int index = searchIndex ('s', name);
|
||||||
|
|
||||||
|
if (index!=-1)
|
||||||
|
return index;
|
||||||
|
|
||||||
|
index = searchIndex ('l', name);
|
||||||
|
|
||||||
|
if (index!=-1)
|
||||||
|
return index;
|
||||||
|
|
||||||
|
return searchIndex ('f', name);
|
||||||
|
}
|
||||||
|
|
||||||
void Locals::write (std::ostream& localFile) const
|
void Locals::write (std::ostream& localFile) const
|
||||||
{
|
{
|
||||||
localFile
|
localFile
|
||||||
|
|
|
@ -17,6 +17,8 @@ namespace Compiler
|
||||||
|
|
||||||
const std::vector<std::string>& get (char type) const;
|
const std::vector<std::string>& get (char type) const;
|
||||||
|
|
||||||
|
int searchIndex (char type, const std::string& name) const;
|
||||||
|
|
||||||
bool search (char type, const std::string& name) const;
|
bool search (char type, const std::string& name) const;
|
||||||
|
|
||||||
std::vector<std::string>& get (char type);
|
std::vector<std::string>& get (char type);
|
||||||
|
@ -26,6 +28,9 @@ namespace Compiler
|
||||||
char getType (const std::string& name) const;
|
char getType (const std::string& name) const;
|
||||||
///< 's': short, 'l': long, 'f': float, ' ': does not exist.
|
///< 's': short, 'l': long, 'f': float, ' ': does not exist.
|
||||||
|
|
||||||
|
int getIndex (const std::string& name) const;
|
||||||
|
///< return index for local variable \a name (-1: does not exist).
|
||||||
|
|
||||||
void write (std::ostream& localFile) const;
|
void write (std::ostream& localFile) const;
|
||||||
///< write declarations to file.
|
///< write declarations to file.
|
||||||
|
|
||||||
|
|
62
components/interpreter/docs/vmformat.txt
Normal file
62
components/interpreter/docs/vmformat.txt
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
Note: a word is considered to be 32 bit long.
|
||||||
|
|
||||||
|
Header (4 words):
|
||||||
|
word: number of words in code block
|
||||||
|
word: number of words in integer literal block
|
||||||
|
word: number of words in float literal block
|
||||||
|
word: number of words in string literal block
|
||||||
|
|
||||||
|
Body (variable length):
|
||||||
|
code block
|
||||||
|
integer literal block (contains a collection of 1 word long integers)
|
||||||
|
float literal block (contains a collection of 1 word long floating point numbers)
|
||||||
|
string literal block (contains a collection of strings of variable length, word-padded)
|
||||||
|
|
||||||
|
Code bit-patterns:
|
||||||
|
|
||||||
|
3322222222221111111111
|
||||||
|
10987654321098765432109876543210
|
||||||
|
00ccccccAAAAAAAAAAAAAAAAAAAAAAAA segment 0: 64 opcodes, 1 24-bit argument
|
||||||
|
01ccccccAAAAAAAAAAAABBBBBBBBBBBB segment 1: 64 opcodes, 2 12-bit arguments
|
||||||
|
10ccccccccccAAAAAAAAAAAAAAAAAAAA segment 2: 1024 opcodes, 1 20-bit argument
|
||||||
|
110000ccccccccccAAAAAAAAAAAAAAAA segment 3: 1024 opcodes, 1 16-bit argument
|
||||||
|
110001ccccccccccAAAAAAAABBBBBBBB segment 4: 1024 opcodes, 2 8-bit arguments
|
||||||
|
110010cccccccccccccccccccccccccc segment 5: 67108864 opcodes, no arguments
|
||||||
|
other bit-patterns reserved
|
||||||
|
|
||||||
|
legent:
|
||||||
|
c: code
|
||||||
|
A: argument 0
|
||||||
|
B: argument 1
|
||||||
|
|
||||||
|
Segment 0:
|
||||||
|
op 0: push A
|
||||||
|
opcodes 1-31 unused
|
||||||
|
opcodes 32-63 reserved for extensions
|
||||||
|
|
||||||
|
Segment 1:
|
||||||
|
opcodes 0-31 unused
|
||||||
|
opcodes 32-63 reserved for extensions
|
||||||
|
|
||||||
|
Segment 2:
|
||||||
|
opcodes 0-511 unused
|
||||||
|
opcodes 512-1023 reserved for extensions
|
||||||
|
|
||||||
|
Segment 3:
|
||||||
|
opcodes 0-511 unused
|
||||||
|
opcodes 512-1023 reserved for extensions
|
||||||
|
|
||||||
|
Segment 4:
|
||||||
|
opcodes 0-511 unused
|
||||||
|
opcodes 512-1023 reserved for extensions
|
||||||
|
|
||||||
|
Segment 5:
|
||||||
|
op 0: store stack[0] in local short stack[1] and pop twice
|
||||||
|
op 1: store stack[0] in local long stack[1] and pop twice
|
||||||
|
op 2: store stack[0] in local float stack[1] and pop twice
|
||||||
|
op 3: convert stack[0] from integer to float
|
||||||
|
op 4: replace stack[0] with integer literal index stack[0]
|
||||||
|
op 5: replace stack[0] with float literal index stack[0]
|
||||||
|
opcodes 6-33554431 unused
|
||||||
|
opcodes 33554432-67108863 reserved for extensions
|
||||||
|
|
|
@ -7,9 +7,9 @@ namespace Interpreter
|
||||||
|
|
||||||
typedef unsigned int Type_Data; // 32 bit
|
typedef unsigned int Type_Data; // 32 bit
|
||||||
|
|
||||||
typedef unsigned int Type_Integer; // 32 bit
|
typedef int Type_Integer; // 32 bit
|
||||||
|
|
||||||
typedef unsigned int Type_Float; // 32 bit
|
typedef float Type_Float; // 32 bit
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue