initial commit
This commit is contained in:
commit
837bc19293
31
LightScript.sln
Normal file
31
LightScript.sln
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio 15
|
||||||
|
VisualStudioVersion = 15.0.27004.2006
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LightScript", "LightScript\LightScript.vcxproj", "{99DA223F-E88F-4E97-A314-E798486955A8}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
|
Debug|x86 = Debug|x86
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
Release|x86 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{99DA223F-E88F-4E97-A314-E798486955A8}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{99DA223F-E88F-4E97-A314-E798486955A8}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{99DA223F-E88F-4E97-A314-E798486955A8}.Debug|x86.ActiveCfg = Debug|Win32
|
||||||
|
{99DA223F-E88F-4E97-A314-E798486955A8}.Debug|x86.Build.0 = Debug|Win32
|
||||||
|
{99DA223F-E88F-4E97-A314-E798486955A8}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{99DA223F-E88F-4E97-A314-E798486955A8}.Release|x64.Build.0 = Release|x64
|
||||||
|
{99DA223F-E88F-4E97-A314-E798486955A8}.Release|x86.ActiveCfg = Release|Win32
|
||||||
|
{99DA223F-E88F-4E97-A314-E798486955A8}.Release|x86.Build.0 = Release|Win32
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {E7E084EF-B1D4-4770-BAE8-A037A0458A76}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
210
LightScript/AST.cpp
Normal file
210
LightScript/AST.cpp
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
#include "AST.h"
|
||||||
|
#include "ByteCode.h"
|
||||||
|
|
||||||
|
int ls::AST_Ident::generateCode(GenerationContext & t)
|
||||||
|
{
|
||||||
|
t.push(code_t::push, BoxedVar(name));
|
||||||
|
t.push(code_t::load);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ls::AST_SentenceList::generateCode(GenerationContext & t)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
for (auto & it : sentences) {
|
||||||
|
ret += it->generateCode(t);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ls::AST_CommonSentence::generateCode(GenerationContext & t)
|
||||||
|
{
|
||||||
|
int ret = expression->generateCode(t);
|
||||||
|
t.push(code_t::pop);
|
||||||
|
return ret + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ls::AST_VarSentence::generateCode(GenerationContext & t)
|
||||||
|
{
|
||||||
|
int ret = RHS->generateCode(t);
|
||||||
|
t.push(code_t::push, BoxedVar(LHS->name));
|
||||||
|
t.push(code_t::new_var);
|
||||||
|
return ret + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ls::AST_AssignmentSentence::generateCode(GenerationContext & t)
|
||||||
|
{
|
||||||
|
int ret = RHS->generateCode(t);
|
||||||
|
ret += LHS->generateCode(t);
|
||||||
|
t.push(code_t::store);
|
||||||
|
return ret + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ls::AST_Binary::generateCode(GenerationContext & t)
|
||||||
|
{
|
||||||
|
int ret = RHS->generateCode(t);
|
||||||
|
ret += LHS->generateCode(t);
|
||||||
|
t.push(static_cast<code_t>(op));
|
||||||
|
return ret + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ls::AST_Unary::generateCode(GenerationContext & t)
|
||||||
|
{
|
||||||
|
int ret = LHS->generateCode(t);
|
||||||
|
t.push(static_cast<code_t>(op));
|
||||||
|
return ret + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ls::AST_While::generateCode(GenerationContext & t)
|
||||||
|
{
|
||||||
|
t.loopStart();
|
||||||
|
int ret = condition->generateCode(t);
|
||||||
|
t.push(code_t::push, BoxedVar());
|
||||||
|
auto e = t.currentPos();
|
||||||
|
t.push(code_t::jf);
|
||||||
|
ret += 2;
|
||||||
|
auto r = ret;
|
||||||
|
t.push(code_t::enterScope);
|
||||||
|
ret++;
|
||||||
|
ret += sentences->generateCode(t);
|
||||||
|
t.push(code_t::leaveScope);
|
||||||
|
ret++;
|
||||||
|
ret++;
|
||||||
|
t.push(code_t::push, BoxedVar(-ret));
|
||||||
|
t.push(code_t::jmp);
|
||||||
|
ret++;
|
||||||
|
t.loopEnd();
|
||||||
|
t.set(e, BoxedVar(ret + 1 - r));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ls::AST_If::generateCode(GenerationContext & t)
|
||||||
|
{
|
||||||
|
int ret = condition->generateCode(t);
|
||||||
|
ret++;
|
||||||
|
t.push(code_t::push, BoxedVar());
|
||||||
|
auto r = ret;
|
||||||
|
auto e = t.currentPos();
|
||||||
|
t.push(code_t::jf);
|
||||||
|
t.push(code_t::enterScope);
|
||||||
|
ret += 3;
|
||||||
|
ret += ifSentence->generateCode(t);
|
||||||
|
t.push(code_t::leaveScope);
|
||||||
|
ret++;
|
||||||
|
t.set(e, BoxedVar(ret - r + (elseSentence != nullptr ? 1 : 0) /*뒤의 명령어 갯수*/));
|
||||||
|
if (elseSentence != nullptr) {
|
||||||
|
t.push(code_t::jmp, BoxedVar());
|
||||||
|
auto cur = ret;
|
||||||
|
auto code_operand_address = t.currentPos();
|
||||||
|
t.push(code_t::enterScope);
|
||||||
|
ret++;
|
||||||
|
ret += elseSentence->generateCode(t);
|
||||||
|
t.push(code_t::leaveScope);
|
||||||
|
ret++;
|
||||||
|
t.set(code_operand_address, BoxedVar(ret - cur));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ls::AST_Dot::generateCode(GenerationContext & t)
|
||||||
|
{
|
||||||
|
int ret = 2;
|
||||||
|
t.push(code_t::push, BoxedVar(RHS->name));
|
||||||
|
ret += LHS->generateCode(t);
|
||||||
|
t.push(code_t::ref);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ls::AST_Index::generateCode(GenerationContext & t)
|
||||||
|
{
|
||||||
|
int ret = 1;
|
||||||
|
ret += RHS->generateCode(t);
|
||||||
|
ret += LHS->generateCode(t);
|
||||||
|
t.push(code_t::ref);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ls::AST_ForIn::generateCode(GenerationContext & t)
|
||||||
|
{
|
||||||
|
int ret = 1;
|
||||||
|
t.push(code_t::enterScope);
|
||||||
|
ret += iterable->generateCode(t);
|
||||||
|
t.push(code_t::getiter);
|
||||||
|
t.push(code_t::push, BoxedVar());
|
||||||
|
t.push(code_t::push, BoxedVar(id->name));
|
||||||
|
t.push(code_t::new_var);
|
||||||
|
ret += 4;
|
||||||
|
t.loopStart();
|
||||||
|
{
|
||||||
|
t.push(code_t::isEnd);
|
||||||
|
t.push(code_t::push, BoxedVar(3));
|
||||||
|
t.push(code_t::jf);
|
||||||
|
t.registerBreak();
|
||||||
|
t.push(code_t::getvalue);
|
||||||
|
t.push(code_t::push, BoxedVar(id->name));
|
||||||
|
t.push(code_t::store);
|
||||||
|
ret += 8;
|
||||||
|
ret += sentences->generateCode(t);
|
||||||
|
t.push(code_t::next);
|
||||||
|
ret++;
|
||||||
|
}
|
||||||
|
ret += t.registerContinue();
|
||||||
|
t.push(code_t::pop);
|
||||||
|
t.push(code_t::leaveScope);
|
||||||
|
ret += 2;
|
||||||
|
t.loopEnd();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ls::AST_CallExpr::generateCode(GenerationContext & t)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
int argnum = 0;
|
||||||
|
for (auto it = args.rbegin(); it != args.rend(); it++) {
|
||||||
|
ret += (*it)->generateCode(t);
|
||||||
|
argnum++;
|
||||||
|
}
|
||||||
|
t.push(code_t::push, BoxedVar(argnum));
|
||||||
|
ret++;
|
||||||
|
ret += callee->generateCode(t);
|
||||||
|
t.push(code_t::call);
|
||||||
|
return ret + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ls::AST_Break::generateCode(GenerationContext & t)
|
||||||
|
{
|
||||||
|
return t.registerBreak();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ls::AST_Continue::generateCode(GenerationContext & t)
|
||||||
|
{
|
||||||
|
return t.registerContinue();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ls::AST_Function::generateCode(GenerationContext & t)
|
||||||
|
{ //일단 가변적인 인자 고려없이 이렇게 짬.
|
||||||
|
static int64_t num=0;
|
||||||
|
auto c = std::unique_ptr<FunctionCode, FunctionCodeDeleter>(new FunctionCode);
|
||||||
|
auto presentFrame = t.getFrame();
|
||||||
|
t.setFrame(c.get());
|
||||||
|
{
|
||||||
|
t.push(code_t::pop);
|
||||||
|
t.push(code_t::enterScope);
|
||||||
|
for (auto & it : args){
|
||||||
|
t.push(code_t::push, BoxedVar(it->name));
|
||||||
|
t.push(code_t::new_var);
|
||||||
|
}
|
||||||
|
sentences->generateCode(t);
|
||||||
|
}
|
||||||
|
t.setFrame(presentFrame);
|
||||||
|
t.push(code_t::push, BoxedVar( std::to_string(num++), move(c) )
|
||||||
|
);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ls::AST_Return::generateCode(GenerationContext & t)
|
||||||
|
{
|
||||||
|
int ret = return_value->generateCode(t);
|
||||||
|
t.push(code_t::ret);
|
||||||
|
return ret + 1;
|
||||||
|
}
|
439
LightScript/AST.h
Normal file
439
LightScript/AST.h
Normal file
@ -0,0 +1,439 @@
|
|||||||
|
#include<string>
|
||||||
|
#include<memory>
|
||||||
|
#include<ostream>
|
||||||
|
#include<cstdint>
|
||||||
|
#include<list>
|
||||||
|
|
||||||
|
#include"Operators.h"
|
||||||
|
#include"CompoundType.h"
|
||||||
|
#include"CodeGeneration.h"
|
||||||
|
#include"LuaScriptGeneration.h"
|
||||||
|
|
||||||
|
#ifndef LS_AST_H_
|
||||||
|
#define LS_AST_H_
|
||||||
|
namespace ls {
|
||||||
|
using std::move;
|
||||||
|
|
||||||
|
class AST_Sentence
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual int generateCode(GenerationContext &) = 0;
|
||||||
|
virtual void printDebugInfo(std::ostream &) = 0;
|
||||||
|
virtual void luaCodeGen(LuaScriptGenerateContext &) = 0;
|
||||||
|
virtual ~AST_Sentence() {}
|
||||||
|
};
|
||||||
|
class AST_SentenceList : public AST_Sentence {
|
||||||
|
public:
|
||||||
|
virtual int generateCode(GenerationContext &);
|
||||||
|
void push_back(std::unique_ptr<AST_Sentence> s) {
|
||||||
|
sentences.emplace_back(move(s));
|
||||||
|
}
|
||||||
|
virtual void printDebugInfo(std::ostream & os) override {
|
||||||
|
for (auto & it : sentences) {
|
||||||
|
it->printDebugInfo(os);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
virtual void luaCodeGen(LuaScriptGenerateContext & lsgc) override {
|
||||||
|
for (auto & it : sentences)
|
||||||
|
{
|
||||||
|
lsgc.sentence_tap();
|
||||||
|
it->luaCodeGen(lsgc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::list< std::unique_ptr<AST_Sentence> > sentences;
|
||||||
|
};
|
||||||
|
class AST_Expr {
|
||||||
|
public:
|
||||||
|
virtual int generateCode(GenerationContext &) = 0;
|
||||||
|
virtual void luaCodeGen(LuaScriptGenerateContext &) = 0;
|
||||||
|
//Twin String 만들어야지. 나중에 바꾼다.
|
||||||
|
virtual void printDebugInfo(std::ostream &) = 0;
|
||||||
|
virtual ~AST_Expr() {}
|
||||||
|
};
|
||||||
|
//Lvalue 표현식 생각 날 때까지 미룸.
|
||||||
|
class AST_Variable : public AST_Expr {};
|
||||||
|
|
||||||
|
class AST_Ident : public AST_Variable {
|
||||||
|
public:
|
||||||
|
explicit AST_Ident(const std::string & s) :name(s) {}
|
||||||
|
virtual int generateCode(GenerationContext &) override;
|
||||||
|
|
||||||
|
virtual void printDebugInfo(std::ostream & os) {
|
||||||
|
os << name;
|
||||||
|
}
|
||||||
|
virtual void luaCodeGen(LuaScriptGenerateContext & lsgc) override {
|
||||||
|
lsgc.out() << name;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
};
|
||||||
|
inline std::ostream & operator<<(std::ostream & os, std::unique_ptr<AST_Sentence> & rhs) {
|
||||||
|
rhs->printDebugInfo(os);
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
inline std::ostream & operator<<(std::ostream & os, std::unique_ptr<AST_SentenceList> & rhs) {
|
||||||
|
rhs->printDebugInfo(os);
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
inline std::ostream & operator<<(std::ostream & os, std::unique_ptr<AST_Expr> & rhs) {
|
||||||
|
rhs->printDebugInfo(os);
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
inline std::ostream & operator<<(std::ostream & os, std::unique_ptr<AST_Variable> & rhs) {
|
||||||
|
rhs->printDebugInfo(os);
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
inline std::ostream & operator<<(std::ostream & os, std::unique_ptr<AST_Ident> & rhs) {
|
||||||
|
rhs->printDebugInfo(os);
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
class AST_CommonSentence : public AST_Sentence {
|
||||||
|
public:
|
||||||
|
explicit AST_CommonSentence(std::unique_ptr<AST_Expr> expr) :expression(move(expr)) {}
|
||||||
|
virtual int generateCode(GenerationContext &);
|
||||||
|
virtual void printDebugInfo(std::ostream & os) override {
|
||||||
|
os << expression << "\n";
|
||||||
|
}
|
||||||
|
virtual void luaCodeGen(LuaScriptGenerateContext & lsgc) override {
|
||||||
|
expression->luaCodeGen(lsgc);
|
||||||
|
lsgc.out() << "\n";
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::unique_ptr<AST_Expr> expression;
|
||||||
|
};
|
||||||
|
class AST_VarSentence : public AST_Sentence {
|
||||||
|
public:
|
||||||
|
AST_VarSentence(std::unique_ptr<AST_Ident> lhs, std::unique_ptr<AST_Expr> rhs)
|
||||||
|
:LHS(move(lhs)), RHS(move(rhs)) {}
|
||||||
|
virtual int generateCode(GenerationContext & t);
|
||||||
|
virtual void printDebugInfo(std::ostream & os) override {
|
||||||
|
os <<"var "<< LHS <<" = " << RHS << "\n";
|
||||||
|
}
|
||||||
|
virtual void luaCodeGen(LuaScriptGenerateContext & lsgc) override {
|
||||||
|
if (lsgc.depth > 0){
|
||||||
|
lsgc.out() << "local ";
|
||||||
|
}
|
||||||
|
lsgc.out() << LHS->name << " = ";
|
||||||
|
RHS->luaCodeGen(lsgc);
|
||||||
|
lsgc.out() << "\n";
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::unique_ptr<AST_Ident> LHS;
|
||||||
|
std::unique_ptr<AST_Expr> RHS;
|
||||||
|
};
|
||||||
|
class AST_AssignmentSentence : public AST_Sentence {
|
||||||
|
public:
|
||||||
|
AST_AssignmentSentence(std::unique_ptr<AST_Expr> lhs, std::unique_ptr<AST_Expr> rhs)
|
||||||
|
:LHS(move(lhs)), RHS(move(rhs)) {}
|
||||||
|
virtual int generateCode(GenerationContext & t);
|
||||||
|
virtual void printDebugInfo(std::ostream & os) override {
|
||||||
|
os << LHS << " = " << RHS << "\n";
|
||||||
|
}
|
||||||
|
virtual void luaCodeGen(LuaScriptGenerateContext & lsgc) override {
|
||||||
|
LHS->luaCodeGen(lsgc);
|
||||||
|
lsgc.out() << " = ";
|
||||||
|
RHS->luaCodeGen(lsgc);
|
||||||
|
lsgc.out() << "\n";
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::unique_ptr<AST_Expr> LHS;
|
||||||
|
std::unique_ptr<AST_Expr> RHS;
|
||||||
|
};
|
||||||
|
class AST_If : public AST_Sentence {
|
||||||
|
public:
|
||||||
|
explicit AST_If(std::unique_ptr<AST_Expr> cond, std::unique_ptr<AST_SentenceList> s)
|
||||||
|
:condition(move(cond)), ifSentence(move(s)),elseSentence(nullptr) {}
|
||||||
|
virtual int generateCode(GenerationContext &);
|
||||||
|
void setElse(std::unique_ptr<AST_SentenceList> e) { elseSentence = move(e); }
|
||||||
|
virtual void printDebugInfo(std::ostream & os) override {
|
||||||
|
os << "if " << condition << " then\n";
|
||||||
|
os << ifSentence;
|
||||||
|
if (elseSentence != nullptr)
|
||||||
|
os << "else\n" << elseSentence;
|
||||||
|
os << "end\n";
|
||||||
|
}
|
||||||
|
virtual void luaCodeGen(LuaScriptGenerateContext & lsgc) override {
|
||||||
|
lsgc.out() << "if ";
|
||||||
|
condition->luaCodeGen(lsgc);
|
||||||
|
lsgc.out() << " then\n";
|
||||||
|
lsgc.depth++;
|
||||||
|
ifSentence->luaCodeGen(lsgc);
|
||||||
|
if (elseSentence != nullptr) {
|
||||||
|
lsgc.out() << "else\n";
|
||||||
|
elseSentence->luaCodeGen(lsgc);
|
||||||
|
}
|
||||||
|
lsgc.out() << "end\n";
|
||||||
|
lsgc.depth--;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::unique_ptr<AST_Expr> condition;
|
||||||
|
std::unique_ptr<AST_SentenceList> ifSentence;
|
||||||
|
std::unique_ptr<AST_SentenceList> elseSentence;
|
||||||
|
};
|
||||||
|
class AST_While : public AST_Sentence {
|
||||||
|
public:
|
||||||
|
explicit AST_While(std::unique_ptr<AST_Expr> cond, std::unique_ptr<AST_SentenceList> s)
|
||||||
|
:condition(move(cond)),sentences(move(s)) {}
|
||||||
|
virtual int generateCode(GenerationContext &);
|
||||||
|
virtual void printDebugInfo(std::ostream & os) override {
|
||||||
|
os << "while " << condition << " do\n";
|
||||||
|
sentences->printDebugInfo(os);
|
||||||
|
os << "end\n";
|
||||||
|
}
|
||||||
|
virtual void luaCodeGen(LuaScriptGenerateContext & lsgc) override {
|
||||||
|
lsgc.out() << "while ";
|
||||||
|
condition->luaCodeGen(lsgc);
|
||||||
|
lsgc.out() << " do\n";
|
||||||
|
lsgc.depth++;
|
||||||
|
sentences->luaCodeGen(lsgc);
|
||||||
|
lsgc.out() << "end\n";
|
||||||
|
lsgc.depth--;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::unique_ptr<AST_Expr> condition;
|
||||||
|
std::unique_ptr<AST_SentenceList> sentences;
|
||||||
|
};
|
||||||
|
class AST_ForIn : public AST_Sentence {
|
||||||
|
public:
|
||||||
|
explicit AST_ForIn(std::unique_ptr<AST_Ident> i,std::unique_ptr<AST_Expr> cond,
|
||||||
|
std::unique_ptr<AST_SentenceList> s)
|
||||||
|
:id(move(i)),iterable(move(cond)),sentences(move(s)) {}
|
||||||
|
virtual int generateCode(GenerationContext &);
|
||||||
|
virtual void printDebugInfo(std::ostream & os) override {
|
||||||
|
os << "for " << id << " in " << iterable << " do\n";
|
||||||
|
sentences->printDebugInfo(os);
|
||||||
|
os << "end\n";
|
||||||
|
}
|
||||||
|
virtual void luaCodeGen(LuaScriptGenerateContext & lsgc) override {
|
||||||
|
lsgc.out() << "for " << id->name << ", _ in pairs(";
|
||||||
|
iterable->luaCodeGen(lsgc);
|
||||||
|
lsgc.out() << ") do\n";
|
||||||
|
lsgc.depth++;
|
||||||
|
sentences->luaCodeGen(lsgc);
|
||||||
|
lsgc.out() << "end\n";
|
||||||
|
lsgc.depth--;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::unique_ptr<AST_Ident> id;
|
||||||
|
std::unique_ptr<AST_Expr> iterable;
|
||||||
|
std::unique_ptr<AST_SentenceList> sentences;
|
||||||
|
};
|
||||||
|
class AST_Break : public AST_Sentence {
|
||||||
|
public:
|
||||||
|
explicit AST_Break() {}
|
||||||
|
virtual int generateCode(GenerationContext &);
|
||||||
|
virtual void printDebugInfo(std::ostream & os) override {
|
||||||
|
os << "break\n";
|
||||||
|
}
|
||||||
|
virtual void luaCodeGen(LuaScriptGenerateContext & lsgc) override {
|
||||||
|
lsgc.out() << "break\n";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
class AST_Continue : public AST_Sentence {
|
||||||
|
public:
|
||||||
|
explicit AST_Continue() {}
|
||||||
|
virtual int generateCode(GenerationContext &);
|
||||||
|
virtual void printDebugInfo(std::ostream & os) override {
|
||||||
|
os << "continue\n";
|
||||||
|
}
|
||||||
|
virtual void luaCodeGen(LuaScriptGenerateContext & lsgc) override {
|
||||||
|
lsgc.out() << "continue\n";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
class AST_Return : public AST_Sentence {
|
||||||
|
public:
|
||||||
|
explicit AST_Return(std::unique_ptr<AST_Expr> r)
|
||||||
|
:return_value(move(r)){}
|
||||||
|
virtual int generateCode(GenerationContext &);
|
||||||
|
virtual void printDebugInfo(std::ostream & os) override {
|
||||||
|
os << "return " << return_value << "\n";
|
||||||
|
}
|
||||||
|
virtual void luaCodeGen(LuaScriptGenerateContext & lsgc) override {
|
||||||
|
lsgc.out() << "return ";
|
||||||
|
return_value->luaCodeGen(lsgc);
|
||||||
|
lsgc.out() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<AST_Expr> return_value;
|
||||||
|
};
|
||||||
|
class AST_Binary : public AST_Expr {
|
||||||
|
public:
|
||||||
|
explicit AST_Binary(Opers oper, std::unique_ptr<AST_Expr> l, std::unique_ptr<AST_Expr> r)
|
||||||
|
:op(oper), LHS(move(l)), RHS(std::move(r)) {}
|
||||||
|
virtual int generateCode(GenerationContext &);
|
||||||
|
virtual void printDebugInfo(std::ostream & os) {
|
||||||
|
os << LHS << " " << to_string(op) << " " << RHS;
|
||||||
|
}
|
||||||
|
virtual void luaCodeGen(LuaScriptGenerateContext & lsgc) override {
|
||||||
|
LHS->luaCodeGen(lsgc);
|
||||||
|
lsgc.out() << to_string(op);
|
||||||
|
RHS->luaCodeGen(lsgc);
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
Opers op;
|
||||||
|
std::unique_ptr<AST_Expr> LHS, RHS;
|
||||||
|
};
|
||||||
|
class AST_Unary : public AST_Expr {
|
||||||
|
public:
|
||||||
|
explicit AST_Unary(Opers oper, std::unique_ptr<AST_Expr> l) :op(oper)
|
||||||
|
, LHS(move(l)) {}
|
||||||
|
virtual int generateCode(GenerationContext &);
|
||||||
|
virtual void printDebugInfo(std::ostream & os) {
|
||||||
|
os << to_string(op) << " " << LHS;
|
||||||
|
}
|
||||||
|
virtual void luaCodeGen(LuaScriptGenerateContext & lsgc) override {
|
||||||
|
if(op != Opers::kPlus)
|
||||||
|
lsgc.out() << to_string(op);
|
||||||
|
LHS->luaCodeGen(lsgc);
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
Opers op;
|
||||||
|
std::unique_ptr<AST_Expr> LHS;
|
||||||
|
};
|
||||||
|
class AST_Index : public AST_Variable {
|
||||||
|
public:
|
||||||
|
explicit AST_Index(std::unique_ptr<AST_Expr> l, std::unique_ptr<AST_Expr> r)
|
||||||
|
:LHS(move(l)), RHS(std::move(r)) {}
|
||||||
|
virtual int generateCode(GenerationContext &);
|
||||||
|
virtual void printDebugInfo(std::ostream & os) {
|
||||||
|
os << LHS << "[" << RHS << "]";
|
||||||
|
}
|
||||||
|
virtual void luaCodeGen(LuaScriptGenerateContext & lsgc) override {
|
||||||
|
LHS->luaCodeGen(lsgc);
|
||||||
|
lsgc.out() << "[";
|
||||||
|
RHS->luaCodeGen(lsgc);
|
||||||
|
lsgc.out() << "]";
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
std::unique_ptr<AST_Expr> LHS, RHS;
|
||||||
|
};
|
||||||
|
class AST_Dot : public AST_Variable {
|
||||||
|
public:
|
||||||
|
explicit AST_Dot(std::unique_ptr<AST_Expr> l, std::unique_ptr<AST_Ident> r)
|
||||||
|
:LHS(move(l)), RHS(std::move(r)) {}
|
||||||
|
virtual int generateCode(GenerationContext &);
|
||||||
|
virtual void printDebugInfo(std::ostream & os) {
|
||||||
|
os << LHS << "." << RHS;
|
||||||
|
}
|
||||||
|
virtual void luaCodeGen(LuaScriptGenerateContext & lsgc) override {
|
||||||
|
LHS->luaCodeGen(lsgc);
|
||||||
|
lsgc.out() << "." << RHS->name;
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
std::unique_ptr<AST_Expr> LHS;
|
||||||
|
std::unique_ptr<AST_Ident> RHS;
|
||||||
|
};
|
||||||
|
class AST_CallExpr : public AST_Variable {
|
||||||
|
public:
|
||||||
|
explicit AST_CallExpr(std::unique_ptr<AST_Expr> l)
|
||||||
|
:callee(move(l)){}
|
||||||
|
void push_back(std::unique_ptr<AST_Expr> arg) { args.emplace_back(move(arg)); }
|
||||||
|
virtual int generateCode(GenerationContext &);
|
||||||
|
virtual void printDebugInfo(std::ostream & os) {
|
||||||
|
os << callee << "(";
|
||||||
|
if (args.size() != 0) {
|
||||||
|
auto it = args.begin();
|
||||||
|
os << *it++;
|
||||||
|
while (it != args.end()) {
|
||||||
|
os << "," << *it++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
os << ")";
|
||||||
|
}
|
||||||
|
virtual void luaCodeGen(LuaScriptGenerateContext & lsgc) override {
|
||||||
|
lsgc.out() << callee << "(";
|
||||||
|
if (args.size() != 0) {
|
||||||
|
auto it = args.begin();
|
||||||
|
(*it++)->luaCodeGen(lsgc);
|
||||||
|
while (it != args.end()) {
|
||||||
|
lsgc.out() << ",";
|
||||||
|
(*it++)->luaCodeGen(lsgc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lsgc.out() << ")";
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
std::unique_ptr<AST_Expr> callee;
|
||||||
|
std::list<std::unique_ptr<AST_Expr>> args;
|
||||||
|
};
|
||||||
|
class AST_Function : public AST_Expr {
|
||||||
|
public:
|
||||||
|
void push_back(std::unique_ptr<AST_Ident> arg) { args.emplace_back(move(arg)); }
|
||||||
|
void setSentenceList(std::unique_ptr<AST_SentenceList> s) { sentences = move(s); }
|
||||||
|
virtual int generateCode(GenerationContext &);
|
||||||
|
virtual void printDebugInfo(std::ostream & os) {
|
||||||
|
os << "fn " << "(";
|
||||||
|
if (args.size() != 0) {
|
||||||
|
auto it = args.begin();
|
||||||
|
os << *it++;
|
||||||
|
while (it != args.end()) {
|
||||||
|
os << "," << *it++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
os << ")\n";
|
||||||
|
os << sentences << "end\n";
|
||||||
|
}
|
||||||
|
virtual void luaCodeGen(LuaScriptGenerateContext & lsgc) override {
|
||||||
|
lsgc.out() << "function" << "(";
|
||||||
|
|
||||||
|
if (args.size() != 0) {
|
||||||
|
auto it = args.begin();
|
||||||
|
lsgc.out() << (*it++)->name;
|
||||||
|
while (it != args.end()) {
|
||||||
|
lsgc.out() << "," << (*it++)->name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lsgc.out() << ")\n";
|
||||||
|
lsgc.depth++;
|
||||||
|
sentences->luaCodeGen(lsgc);
|
||||||
|
lsgc.depth--;
|
||||||
|
lsgc.out() << "end\n";
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
std::list<std::unique_ptr<AST_Ident>> args;
|
||||||
|
std::unique_ptr<AST_SentenceList> sentences;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Ty>
|
||||||
|
class AST_Value : public AST_Expr {
|
||||||
|
public:
|
||||||
|
explicit AST_Value(const Ty & v) :value(v) {}
|
||||||
|
virtual int generateCode(GenerationContext & gctx) override {
|
||||||
|
gctx.push(code_t::push, BoxedVar(value));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
virtual void printDebugInfo(std::ostream & os) {
|
||||||
|
os << value;
|
||||||
|
}
|
||||||
|
virtual void luaCodeGen(LuaScriptGenerateContext & lsgc) override {
|
||||||
|
lsgc.out() << value;
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
Ty value;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AST_Int : public AST_Value<int64_t> {
|
||||||
|
public:
|
||||||
|
using AST_Value<int64_t>::AST_Value;
|
||||||
|
};
|
||||||
|
class AST_Float : public AST_Value<double> {
|
||||||
|
public:
|
||||||
|
using AST_Value<double>::AST_Value;
|
||||||
|
};
|
||||||
|
class AST_None : public AST_Expr {
|
||||||
|
public:
|
||||||
|
virtual int generateCode(GenerationContext & gctx) override {
|
||||||
|
gctx.push(code_t::push, BoxedVar());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
virtual void printDebugInfo(std::ostream & os) {
|
||||||
|
os << "None";
|
||||||
|
}
|
||||||
|
virtual void luaCodeGen(LuaScriptGenerateContext & lsgc) override {
|
||||||
|
lsgc.out() << "nil";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
10
LightScript/BoxedVar.cpp
Normal file
10
LightScript/BoxedVar.cpp
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#include "BoxedVar.h"
|
||||||
|
|
||||||
|
ls::BoxedVar::BoxedVar(const BoxedVar & var)
|
||||||
|
{
|
||||||
|
auto p = var.ptr->copy();
|
||||||
|
if (p == nullptr)
|
||||||
|
ptr = var.ptr;
|
||||||
|
else
|
||||||
|
ptr = p;
|
||||||
|
}
|
44
LightScript/BoxedVar.h
Normal file
44
LightScript/BoxedVar.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#include<string>
|
||||||
|
#include<cstdint>
|
||||||
|
#include"CompoundType.h"
|
||||||
|
|
||||||
|
#ifndef LS_BoxedVar_H_
|
||||||
|
#define LS_BoxedVar_H_
|
||||||
|
namespace ls {
|
||||||
|
struct function_tag {};
|
||||||
|
class BoxedVar {
|
||||||
|
public:
|
||||||
|
BoxedVar() :
|
||||||
|
ptr(createVar()) {}
|
||||||
|
explicit BoxedVar(bool b):
|
||||||
|
ptr(createVar(b)) {}
|
||||||
|
explicit BoxedVar(int64_t i) :
|
||||||
|
ptr(createVar(i)) {}
|
||||||
|
explicit BoxedVar(int i) :
|
||||||
|
ptr(createVar(i)) {}
|
||||||
|
explicit BoxedVar(double d) :
|
||||||
|
ptr(createVar(d)) {}
|
||||||
|
explicit BoxedVar(const std::string & str) :
|
||||||
|
ptr(createVar(str)) {}
|
||||||
|
explicit BoxedVar(const std::string & name, std::unique_ptr<FunctionCode, FunctionCodeDeleter> t) :
|
||||||
|
ptr(createVar(name,move(t))) {}
|
||||||
|
explicit BoxedVar(std::function<std::shared_ptr<CompoundType>(std::vector<BoxedVar>&)> t, function_tag) :
|
||||||
|
ptr(createVar(t)) {}
|
||||||
|
BoxedVar(const BoxedVar & var);
|
||||||
|
explicit BoxedVar(const std::shared_ptr<CompoundType> & t)
|
||||||
|
:ptr(t){}
|
||||||
|
explicit BoxedVar(const std::shared_ptr<CompoundType> && t)
|
||||||
|
:ptr(std::move(t)) {}
|
||||||
|
|
||||||
|
std::shared_ptr<CompoundType> get() const { return ptr; }
|
||||||
|
void set(const std::shared_ptr<CompoundType> & t) { ptr = t; }
|
||||||
|
|
||||||
|
std::string to_string() const { return ptr->to_string(); }
|
||||||
|
private:
|
||||||
|
std::shared_ptr<CompoundType> ptr;
|
||||||
|
};
|
||||||
|
inline BoxedVar createBoxedFunction(std::function<std::shared_ptr<CompoundType>(std::vector<BoxedVar>&)> t) {
|
||||||
|
return BoxedVar(t, function_tag());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
44
LightScript/ByteCode.cpp
Normal file
44
LightScript/ByteCode.cpp
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#include "ByteCode.h"
|
||||||
|
|
||||||
|
bool ls::isInOpers(code_t c)
|
||||||
|
{
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case ls::code_t::and:
|
||||||
|
case ls::code_t:: or:
|
||||||
|
case ls::code_t::not:
|
||||||
|
case ls::code_t::plus:
|
||||||
|
case ls::code_t::minus:
|
||||||
|
case ls::code_t::add:
|
||||||
|
case ls::code_t::sub:
|
||||||
|
case ls::code_t::mul:
|
||||||
|
case ls::code_t::div:
|
||||||
|
case ls::code_t::eq:
|
||||||
|
case ls::code_t::neq:
|
||||||
|
case ls::code_t::gte:
|
||||||
|
case ls::code_t::gt:
|
||||||
|
case ls::code_t::less:
|
||||||
|
case ls::code_t::leq:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ls::to_string(code_t t)
|
||||||
|
{
|
||||||
|
static const char * lookup[] = { "nop",
|
||||||
|
"and","or","not",
|
||||||
|
"plus","minus",
|
||||||
|
"add","sub","mul","div",
|
||||||
|
"eq","neq","gt","gte","less","leq",
|
||||||
|
"push","pop","load","store","new_var",
|
||||||
|
"jmp","jt","jf",
|
||||||
|
"enterScope","leaveScope",
|
||||||
|
"call","ret","ref","getiter","getvalue",
|
||||||
|
"isEnd","next",
|
||||||
|
};
|
||||||
|
if(t != code_t::ERROR)
|
||||||
|
return lookup[static_cast<size_t>(t)];
|
||||||
|
return "Error";
|
||||||
|
}
|
110
LightScript/ByteCode.h
Normal file
110
LightScript/ByteCode.h
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
|
||||||
|
#include<cstdint>
|
||||||
|
#include<vector>
|
||||||
|
#include<map>
|
||||||
|
#include"Operators.h"
|
||||||
|
#include"BoxedVar.h"
|
||||||
|
|
||||||
|
#ifndef LS_ByteCode_H_
|
||||||
|
#define LS_ByteCode_H_
|
||||||
|
namespace ls {
|
||||||
|
typedef int64_t pos_t;
|
||||||
|
enum class code_t : uint16_t
|
||||||
|
{
|
||||||
|
//아무것도 안함.
|
||||||
|
nop = 0,
|
||||||
|
//스택에서 2개 뽑아서 and 연산 한 다음 스택에 저장.
|
||||||
|
and = kAnd,
|
||||||
|
//스택에서 2개 뽑아서 or 연산 한 다음 스택에 저장.
|
||||||
|
or = kOr,
|
||||||
|
//스택에서 2개 뽑아서 and 연산 한 다음 스택에 저장.
|
||||||
|
not = kNot,
|
||||||
|
|
||||||
|
//스택에서 1개 뽑아서 plus 연산 한 다음 스택에 저장.
|
||||||
|
plus = kPlus,
|
||||||
|
//스택에서 1개 뽑아서 minus 연산 한 다음 스택에 저장.
|
||||||
|
minus = kMinus,
|
||||||
|
//스택에서 2개 뽑아서 더한 다음 스택에 저장.
|
||||||
|
add = kAdd,
|
||||||
|
//스택에서 2개 뽑아서 빼고 스택에 저장.
|
||||||
|
sub = kSub,
|
||||||
|
//스택에서 2개 뽑아서 곱한 다음 스택에 저장.
|
||||||
|
mul = kMul,
|
||||||
|
//스택에서 2개 뽑아서 나눈 다음 스택에 저장.
|
||||||
|
div = kDiv,
|
||||||
|
|
||||||
|
//스택에서 2개 뽑아서 비교한 다음 bool 값을 스택에 저장.
|
||||||
|
eq = kEqual,
|
||||||
|
neq = kNotEqual,
|
||||||
|
gt = kGreater,
|
||||||
|
gte = kEqualGreater,
|
||||||
|
less = kLess,
|
||||||
|
leq = kLessEqual,
|
||||||
|
|
||||||
|
//스택에 하나 저장
|
||||||
|
push,
|
||||||
|
//스택에서 한개 뽑아내기.
|
||||||
|
pop,
|
||||||
|
//스택에서 변수이름 받아서 변수참조 되돌려 주기.
|
||||||
|
load,
|
||||||
|
//스택에서 2개 뽑아서 처음 뽑은 것에다 나중에 뽑은 것 넣기.
|
||||||
|
store,
|
||||||
|
//스택에서 변수이름 받아서 새로운 변수 생성
|
||||||
|
new_var,
|
||||||
|
|
||||||
|
//상대 주소 점프. ProgramCounter 에다 더하면 됨.
|
||||||
|
jmp,
|
||||||
|
//스택에서 1개 뽑아서 참일때 점프
|
||||||
|
jt,
|
||||||
|
//스택에서 1개 뽑아서 거짓일때 점프
|
||||||
|
jf,
|
||||||
|
|
||||||
|
//변수 스코프 진입.
|
||||||
|
enterScope,
|
||||||
|
//스코프에서 나오기.
|
||||||
|
leaveScope,
|
||||||
|
|
||||||
|
//함수 호출
|
||||||
|
call,
|
||||||
|
//참조 operator [] 나 . 으로 멤버 참조하는 거.
|
||||||
|
ref,
|
||||||
|
//return
|
||||||
|
ret,
|
||||||
|
//get iterator from object.
|
||||||
|
getiter,
|
||||||
|
//get value from iterator.
|
||||||
|
getvalue,
|
||||||
|
//true if iterator is terminated, otherwise false.
|
||||||
|
isEnd,
|
||||||
|
//get next sequence iterator.
|
||||||
|
next,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ERROR = 0xffff,
|
||||||
|
};
|
||||||
|
struct instruction {
|
||||||
|
code_t code;
|
||||||
|
pos_t pos = -1;
|
||||||
|
};
|
||||||
|
bool isInOpers(code_t c);
|
||||||
|
std::string to_string(code_t t);
|
||||||
|
|
||||||
|
struct FunctionCode
|
||||||
|
{
|
||||||
|
std::vector<instruction> code;
|
||||||
|
std::vector<BoxedVar> operands;
|
||||||
|
};
|
||||||
|
struct InstructionCode {
|
||||||
|
FunctionCode mainframe;
|
||||||
|
FunctionCode * ptr;
|
||||||
|
explicit InstructionCode() {
|
||||||
|
ptr = &mainframe;
|
||||||
|
}
|
||||||
|
|
||||||
|
FunctionCode * operator->() { return ptr; }
|
||||||
|
const FunctionCode * operator->() const { return ptr; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
37
LightScript/CodeGeneration.cpp
Normal file
37
LightScript/CodeGeneration.cpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include "CodeGeneration.h"
|
||||||
|
|
||||||
|
std::ostream & ls::operator<<(std::ostream & os, const GenerationContext & gc)
|
||||||
|
{
|
||||||
|
for (auto it : (gc.inst)->code)
|
||||||
|
{
|
||||||
|
os << to_string(it.code) << "\t";
|
||||||
|
if (it.pos >= 0)
|
||||||
|
{
|
||||||
|
os << (gc.inst)->operands[it.pos].to_string();
|
||||||
|
}
|
||||||
|
os << "\n";
|
||||||
|
}
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::GenerationContext::loopStart()
|
||||||
|
{
|
||||||
|
lpos.emplace_back();
|
||||||
|
lpos.back().b = inst->code.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::GenerationContext::loopEnd()
|
||||||
|
{
|
||||||
|
int64_t e = inst->code.size();
|
||||||
|
if (lpos.size() == 0)
|
||||||
|
throw std::exception("Depth Error!");
|
||||||
|
for (auto it : lpos.back().break_pos)
|
||||||
|
{
|
||||||
|
set(it.operandPos, BoxedVar(e - it.codePos));
|
||||||
|
}
|
||||||
|
for (auto it : lpos.back().continue_pos)
|
||||||
|
{
|
||||||
|
set(it.operandPos, BoxedVar(lpos.back().b - it.codePos));
|
||||||
|
}
|
||||||
|
lpos.pop_back();
|
||||||
|
}
|
63
LightScript/CodeGeneration.h
Normal file
63
LightScript/CodeGeneration.h
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#include<memory>
|
||||||
|
#include<ostream>
|
||||||
|
#include"ByteCode.h"
|
||||||
|
#include "BoxedVar.h"
|
||||||
|
|
||||||
|
#ifndef LS_CodeGeneration_H_
|
||||||
|
#define LS_CodeGeneration_H_
|
||||||
|
namespace ls {
|
||||||
|
class GenerationContext
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline void push(code_t c) {
|
||||||
|
inst->code.push_back(instruction{ c, -1 });
|
||||||
|
}
|
||||||
|
inline void push(code_t c, BoxedVar var) {
|
||||||
|
inst->operands.push_back(var);
|
||||||
|
inst->code.push_back(instruction{ c, static_cast<int64_t>(inst->operands.size() - 1 )});//errorÀÇ À§Çù. º¸¾È À§Çù.
|
||||||
|
}
|
||||||
|
inline int64_t currentPos() { return inst->operands.size() - 1; }
|
||||||
|
inline void set(int64_t pos, BoxedVar var) { inst->operands[pos] = var; }
|
||||||
|
|
||||||
|
inline int64_t currentCodePos() { return inst->code.size() - 1; }
|
||||||
|
//inline int64_t setCodePos(int64_t pos, code_t c) { inst->code[pos].code = c; }
|
||||||
|
|
||||||
|
void loopStart();
|
||||||
|
void loopEnd();
|
||||||
|
|
||||||
|
|
||||||
|
int registerBreak() {
|
||||||
|
push(code_t::push, BoxedVar());
|
||||||
|
lpos.back().break_pos.push_back({ currentCodePos() + 1,currentPos() });
|
||||||
|
push(code_t::jmp);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
int registerContinue() {
|
||||||
|
push(code_t::push, BoxedVar());
|
||||||
|
lpos.back().continue_pos.push_back({ currentCodePos() + 1,currentPos() });
|
||||||
|
push(code_t::jmp);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
void setFrame(FunctionCode * t) {
|
||||||
|
inst.ptr = t;
|
||||||
|
}
|
||||||
|
FunctionCode * getFrame() { return inst.ptr; }
|
||||||
|
friend std::ostream & operator<<(std::ostream & os, const GenerationContext & a);
|
||||||
|
private:
|
||||||
|
InstructionCode inst;
|
||||||
|
struct LoopPos
|
||||||
|
{
|
||||||
|
struct CodePos{
|
||||||
|
int64_t codePos;
|
||||||
|
int64_t operandPos;
|
||||||
|
};
|
||||||
|
int64_t b;
|
||||||
|
std::vector<CodePos> continue_pos;
|
||||||
|
std::vector<CodePos> break_pos;
|
||||||
|
};
|
||||||
|
std::vector<LoopPos> lpos;
|
||||||
|
};
|
||||||
|
std::ostream & operator<<(std::ostream & os, const GenerationContext & a);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
134
LightScript/CompoundType.cpp
Normal file
134
LightScript/CompoundType.cpp
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
#include <sstream>
|
||||||
|
#include "CompoundType.h"
|
||||||
|
#include"ByteCode.h"
|
||||||
|
|
||||||
|
using namespace ls;
|
||||||
|
|
||||||
|
shared_ptr<CompoundType> ls::CompoundType::binaryGo(Opers op, CompoundType * ptr)
|
||||||
|
{
|
||||||
|
switch (op) {
|
||||||
|
case kEqual:
|
||||||
|
return createVar(this == ptr);
|
||||||
|
break;
|
||||||
|
case kNotEqual:
|
||||||
|
return createVar(this != ptr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_ptr<CompoundType> ls::BooleanType::unaryGo(Opers op)
|
||||||
|
{
|
||||||
|
if (op == kNot) {
|
||||||
|
return createVar(!value);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_ptr<CompoundType> ls::BooleanType::binaryGo(Opers op, CompoundType * rhs)
|
||||||
|
{
|
||||||
|
auto r = dynamic_cast<BooleanType *>(rhs);
|
||||||
|
if (r == nullptr) return nullptr;
|
||||||
|
auto ret = LogicalBinaryGo<bool, bool>(op, value, r->value);
|
||||||
|
if (ret != nullptr) return ret;
|
||||||
|
switch (op) {
|
||||||
|
case kEqual:
|
||||||
|
return createVar(value == r->value);
|
||||||
|
break;
|
||||||
|
case kNotEqual:
|
||||||
|
return createVar(value != r->value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_ptr<CompoundType> ls::BooleanType::copy()
|
||||||
|
{
|
||||||
|
return createVar(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_ptr<CompoundType> ls::IntegerType::unaryGo(Opers op)
|
||||||
|
{
|
||||||
|
return ArithmeticUnaryGo(op, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_ptr<CompoundType> ls::IntegerType::binaryGo(Opers op, CompoundType * rhs)
|
||||||
|
{
|
||||||
|
switch (rhs->Type()) {
|
||||||
|
case kInteger:
|
||||||
|
return ArithmeticBinaryGo(op, value, dynamic_cast<IntegerType *>(rhs)->value);
|
||||||
|
break;
|
||||||
|
case kFloat:
|
||||||
|
return ArithmeticBinaryGo(op, value, dynamic_cast<FloatType *>(rhs)->value);
|
||||||
|
break;
|
||||||
|
case kString:
|
||||||
|
if (op== kAdd){
|
||||||
|
return createVar(to_string() + dynamic_cast<StringType *>(rhs)->value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_ptr<CompoundType> ls::IntegerType::copy()
|
||||||
|
{
|
||||||
|
return createVar(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_ptr<CompoundType> ls::FloatType::unaryGo(Opers op)
|
||||||
|
{
|
||||||
|
return ArithmeticUnaryGo(op, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_ptr<CompoundType> ls::FloatType::binaryGo(Opers op, CompoundType * rhs)
|
||||||
|
{
|
||||||
|
switch (rhs->Type()) {
|
||||||
|
case kInteger:
|
||||||
|
return ArithmeticBinaryGo(op, value, dynamic_cast<IntegerType *>(rhs)->value);
|
||||||
|
break;
|
||||||
|
case kFloat:
|
||||||
|
return ArithmeticBinaryGo(op, value, dynamic_cast<FloatType *>(rhs)->value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_ptr<CompoundType> ls::FloatType::copy()
|
||||||
|
{
|
||||||
|
return createVar(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_ptr<CompoundType> ls::StringType::binaryGo(Opers op, CompoundType * rhs)
|
||||||
|
{
|
||||||
|
if (op != kAdd)
|
||||||
|
return nullptr;
|
||||||
|
return createVar(value + rhs->to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_ptr<CompoundType> ls::StringType::copy()
|
||||||
|
{
|
||||||
|
return createVar(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ls::TableType::to_string()
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "{";
|
||||||
|
for (auto& it : map){
|
||||||
|
ss << it.first->to_string() << "="
|
||||||
|
<< it.second->to_string() << ",";
|
||||||
|
}
|
||||||
|
ss << "}";
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::FunctionCodeDeleter::operator()(FunctionCode * p)
|
||||||
|
{
|
||||||
|
delete p;
|
||||||
|
}
|
312
LightScript/CompoundType.h
Normal file
312
LightScript/CompoundType.h
Normal file
@ -0,0 +1,312 @@
|
|||||||
|
#include<string>
|
||||||
|
#include<cstdint>
|
||||||
|
#include<memory>
|
||||||
|
#include<unordered_map>
|
||||||
|
#include<exception>
|
||||||
|
#include<functional>
|
||||||
|
#include"Operators.h"
|
||||||
|
|
||||||
|
#ifndef LS_CompoundType_H_
|
||||||
|
#define LS_CompoundType_H_
|
||||||
|
namespace ls {
|
||||||
|
using std::shared_ptr;
|
||||||
|
using std::make_shared;
|
||||||
|
|
||||||
|
//순서 바꾸지 마시요.
|
||||||
|
enum TypeKind {
|
||||||
|
kNone = 0,
|
||||||
|
kBoolean,
|
||||||
|
kInteger,
|
||||||
|
kFloat,
|
||||||
|
kString,
|
||||||
|
kTable,
|
||||||
|
kTableIter,
|
||||||
|
kFunction,
|
||||||
|
kFunctionProxy,
|
||||||
|
kUserDefined,
|
||||||
|
kDEF_END
|
||||||
|
};
|
||||||
|
class BoxedVar;
|
||||||
|
struct FunctionCode;
|
||||||
|
//std::unordered_map<std::string, void(IntType::*)()> st;
|
||||||
|
class TypeError : public std::logic_error
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using std::logic_error::logic_error;
|
||||||
|
};
|
||||||
|
class InvalidOperation : public TypeError
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
InvalidOperation() :TypeError("InvalidOperation") {}
|
||||||
|
};
|
||||||
|
class DividedByZero : public TypeError
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DividedByZero() :TypeError("attempt to divide by zero") {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class CompoundType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CompoundType() = default;
|
||||||
|
|
||||||
|
//virtual void searchMethod(const std::string & str) {}
|
||||||
|
virtual BoxedVar * index(CompoundType *) { return nullptr; }
|
||||||
|
|
||||||
|
//바꾸는 것 고려해야함.
|
||||||
|
virtual bool next() { return false; }
|
||||||
|
virtual shared_ptr<CompoundType> unaryGo(Opers op) { return nullptr; }
|
||||||
|
virtual shared_ptr<CompoundType> binaryGo(Opers op, CompoundType *);
|
||||||
|
|
||||||
|
virtual TypeKind Type() = 0;
|
||||||
|
|
||||||
|
virtual shared_ptr<CompoundType> copy() { return nullptr; }
|
||||||
|
|
||||||
|
//virtual std::shared_ptr<CompoundType> cast(TypeKind tk) { throw InvalidOperation(); }
|
||||||
|
virtual std::string to_string() { return "<UnknownObject>"; }
|
||||||
|
virtual ~CompoundType() {}
|
||||||
|
|
||||||
|
virtual size_t hash() { return reinterpret_cast<size_t>(this); }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
namespace std {
|
||||||
|
template<> struct hash<ls::CompoundType *>
|
||||||
|
{
|
||||||
|
typedef ls::CompoundType * argument_type;
|
||||||
|
typedef std::size_t result_type;
|
||||||
|
result_type operator()(argument_type s) const noexcept{
|
||||||
|
return s->hash();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
namespace ls
|
||||||
|
{
|
||||||
|
class NoneType final : public CompoundType {
|
||||||
|
public:
|
||||||
|
virtual TypeKind Type() { return TypeKind::kNone; }
|
||||||
|
virtual std::string to_string() { return "None"; }
|
||||||
|
virtual size_t hash() override { return 0x12345678; };
|
||||||
|
};
|
||||||
|
class BooleanType final : public CompoundType {
|
||||||
|
public:
|
||||||
|
explicit BooleanType(bool b) :value(b) {}
|
||||||
|
virtual TypeKind Type() override { return TypeKind::kBoolean; }
|
||||||
|
virtual std::string to_string() { return value ? "true" : "false"; }
|
||||||
|
virtual shared_ptr<CompoundType> unaryGo(Opers op) override;
|
||||||
|
virtual shared_ptr<CompoundType> binaryGo(Opers op, CompoundType * rhs) override;
|
||||||
|
virtual size_t hash() override { return std::hash<bool>{}(value); };
|
||||||
|
virtual shared_ptr<CompoundType> copy();
|
||||||
|
|
||||||
|
bool value;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IntegerType final : public CompoundType {
|
||||||
|
public:
|
||||||
|
explicit IntegerType(int64_t i) :value(i) {}
|
||||||
|
virtual TypeKind Type() { return TypeKind::kInteger; }
|
||||||
|
virtual std::string to_string() { return std::to_string(value); }
|
||||||
|
virtual shared_ptr<CompoundType> unaryGo(Opers op) override;
|
||||||
|
virtual shared_ptr<CompoundType> binaryGo(Opers op, CompoundType * rhs) override;
|
||||||
|
virtual size_t hash() override { return value; };
|
||||||
|
virtual shared_ptr<CompoundType> copy();
|
||||||
|
|
||||||
|
int64_t value;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FloatType final : public CompoundType {
|
||||||
|
public:
|
||||||
|
explicit FloatType(double i) :value(i) {}
|
||||||
|
virtual TypeKind Type() { return TypeKind::kFloat; }
|
||||||
|
virtual std::string to_string() { return std::to_string(value); }
|
||||||
|
|
||||||
|
virtual shared_ptr<CompoundType> unaryGo(Opers op) override;
|
||||||
|
virtual shared_ptr<CompoundType> binaryGo(Opers op, CompoundType * rhs) override;
|
||||||
|
virtual size_t hash() override { return std::hash<double>{}(value); };
|
||||||
|
virtual shared_ptr<CompoundType> copy();
|
||||||
|
|
||||||
|
double value;
|
||||||
|
};
|
||||||
|
|
||||||
|
class StringType final : public CompoundType {
|
||||||
|
public:
|
||||||
|
explicit StringType(const std::string & str) :value(str) {}
|
||||||
|
virtual TypeKind Type() { return TypeKind::kString; }
|
||||||
|
virtual std::string to_string() { return "\"" + value + "\""; }
|
||||||
|
|
||||||
|
virtual shared_ptr<CompoundType> unaryGo(Opers op) override { return nullptr; }
|
||||||
|
virtual shared_ptr<CompoundType> binaryGo(Opers op, CompoundType * rhs) override;
|
||||||
|
virtual size_t hash() override { return std::hash<std::string>{}(value); };
|
||||||
|
virtual shared_ptr<CompoundType> copy();
|
||||||
|
|
||||||
|
std::string value;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::unordered_map< CompoundType *, shared_ptr<CompoundType> > dict_type;
|
||||||
|
typedef dict_type::iterator dict_iterator_type;
|
||||||
|
|
||||||
|
/*class IterativeType : public CompoundType {
|
||||||
|
};
|
||||||
|
필요할까?
|
||||||
|
*/
|
||||||
|
class TableIterType final : public CompoundType {
|
||||||
|
public:
|
||||||
|
explicit TableIterType(dict_iterator_type it, dict_iterator_type end_iterator)
|
||||||
|
:cur(it), end(end_iterator) {}
|
||||||
|
virtual TypeKind Type() { return TypeKind::kTableIter; }
|
||||||
|
virtual std::string to_string() override {
|
||||||
|
if (cur != end)
|
||||||
|
return cur->first->to_string();
|
||||||
|
else return "<End Iteraor>";
|
||||||
|
}
|
||||||
|
inline virtual bool next() override {
|
||||||
|
if (cur != end)
|
||||||
|
cur++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
inline bool isEnd() {
|
||||||
|
return cur != end;
|
||||||
|
}
|
||||||
|
inline shared_ptr<CompoundType> & value() {
|
||||||
|
return cur->second;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
dict_iterator_type cur;
|
||||||
|
dict_iterator_type end;
|
||||||
|
};
|
||||||
|
class TableType final : public CompoundType {
|
||||||
|
public:
|
||||||
|
explicit TableType() {}
|
||||||
|
virtual TypeKind Type() { return TypeKind::kTable; }
|
||||||
|
virtual std::string to_string() override;
|
||||||
|
virtual shared_ptr<TableIterType> getiter() {
|
||||||
|
return make_shared<TableIterType>(map.begin(), map.end());
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
dict_type map;
|
||||||
|
};
|
||||||
|
class FunctionProxyType : public CompoundType {
|
||||||
|
public:
|
||||||
|
explicit FunctionProxyType(std::function<std::shared_ptr<CompoundType>(std::vector<BoxedVar>&)> v) :value(v) {}
|
||||||
|
std::shared_ptr<CompoundType> call(std::vector<BoxedVar> & stack) {
|
||||||
|
return value(stack);
|
||||||
|
}
|
||||||
|
virtual TypeKind Type() override { return TypeKind::kFunctionProxy; }
|
||||||
|
virtual std::string to_string() override { return debugName; }
|
||||||
|
std::string debugName = "<FunctionProxy>";
|
||||||
|
std::function<std::shared_ptr<CompoundType>(std::vector<BoxedVar>&)> value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FunctionCodeDeleter{
|
||||||
|
void operator()(FunctionCode * );
|
||||||
|
};
|
||||||
|
|
||||||
|
class FunctionType : public CompoundType {
|
||||||
|
public:
|
||||||
|
FunctionType(const std::string & n, std::unique_ptr<FunctionCode, FunctionCodeDeleter> c)
|
||||||
|
:name(n), code(move(c)) {}
|
||||||
|
|
||||||
|
virtual TypeKind Type() override { return TypeKind::kFunction; }
|
||||||
|
virtual std::string to_string() override { return "<Function:"+name+">"; }
|
||||||
|
public:
|
||||||
|
std::string name = "<Function>";
|
||||||
|
std::unique_ptr<FunctionCode, FunctionCodeDeleter> code;
|
||||||
|
};
|
||||||
|
inline std::shared_ptr<CompoundType> createVar(void) {
|
||||||
|
static std::shared_ptr < CompoundType > ret(new NoneType);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
inline std::shared_ptr<CompoundType> createVar(int64_t t) {
|
||||||
|
return std::make_shared<IntegerType>(t);
|
||||||
|
}
|
||||||
|
inline std::shared_ptr<CompoundType> createVar(int t) {
|
||||||
|
return std::make_shared<IntegerType>(t);
|
||||||
|
}
|
||||||
|
inline std::shared_ptr<CompoundType> createVar(bool t) {
|
||||||
|
return std::make_shared<BooleanType>(t);
|
||||||
|
}
|
||||||
|
inline std::shared_ptr<CompoundType> createVar(double t) {
|
||||||
|
return std::make_shared<FloatType>(t);
|
||||||
|
}
|
||||||
|
inline std::shared_ptr<CompoundType> createVar(const std::string & t) {
|
||||||
|
return std::make_shared<StringType>(t);
|
||||||
|
}
|
||||||
|
inline std::shared_ptr<CompoundType> createVar(std::function<std::shared_ptr<CompoundType>(std::vector<BoxedVar>&)> v) {
|
||||||
|
return std::make_shared<FunctionProxyType>(v);
|
||||||
|
}
|
||||||
|
inline std::shared_ptr<CompoundType> createVar(const std::string & name, std::unique_ptr<FunctionCode, FunctionCodeDeleter> t) {
|
||||||
|
return std::make_shared<FunctionType>(name, move(t));
|
||||||
|
}
|
||||||
|
template<typename LHStype,typename RHStype>
|
||||||
|
shared_ptr<CompoundType> LogicalBinaryGo(Opers op,const LHStype & lhs,const RHStype & rhs) {
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case kAnd:
|
||||||
|
return createVar(lhs && rhs);
|
||||||
|
break;
|
||||||
|
case kOr:
|
||||||
|
return createVar(lhs || rhs);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template<typename LHStype>
|
||||||
|
shared_ptr<CompoundType> ArithmeticUnaryGo(Opers op, const LHStype & lhs) {
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case kPlus:
|
||||||
|
return createVar(+lhs);
|
||||||
|
break;
|
||||||
|
case kMinus:
|
||||||
|
return createVar(-lhs);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template<typename LHStype, typename RHStype>
|
||||||
|
shared_ptr<CompoundType> ArithmeticBinaryGo(Opers op, const LHStype & lhs, const RHStype & rhs) {
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case kAdd:
|
||||||
|
return createVar(lhs + rhs);
|
||||||
|
break;
|
||||||
|
case kSub:
|
||||||
|
return createVar(lhs - rhs);
|
||||||
|
break;
|
||||||
|
case kMul:
|
||||||
|
return createVar(lhs * rhs);
|
||||||
|
break;
|
||||||
|
case kDiv:
|
||||||
|
if (rhs == 0){
|
||||||
|
throw DividedByZero();
|
||||||
|
}
|
||||||
|
return createVar(lhs / rhs);
|
||||||
|
break;
|
||||||
|
case kGreater:
|
||||||
|
return createVar(lhs > rhs);
|
||||||
|
break;
|
||||||
|
case kEqualGreater:
|
||||||
|
return createVar(lhs >= rhs);
|
||||||
|
break;
|
||||||
|
case kEqual:
|
||||||
|
return createVar(lhs == rhs);
|
||||||
|
break;
|
||||||
|
case kNotEqual:
|
||||||
|
return createVar(lhs != rhs);
|
||||||
|
break;
|
||||||
|
case kLess:
|
||||||
|
return createVar(lhs < rhs);
|
||||||
|
break;
|
||||||
|
case kLessEqual:
|
||||||
|
return createVar(lhs <= rhs);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
111
LightScript/Lexer.cpp
Normal file
111
LightScript/Lexer.cpp
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
#include<algorithm>
|
||||||
|
#include "Lexer.h"
|
||||||
|
|
||||||
|
using namespace ls;
|
||||||
|
|
||||||
|
static bool isCutCharactor(int ch) {
|
||||||
|
static char s[] = " \n\t+-/*.,!|<>[]{}()&\'\"^%:;~`$#\\?#@=\r\0";
|
||||||
|
auto pos = std::find(std::begin(s), std::end(s), ch);
|
||||||
|
return pos != std::end(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isOperatorWord(int ch) {
|
||||||
|
static char s[] = "+-/*!|<>&^%~$?=(),";
|
||||||
|
auto pos = std::find(std::begin(s), std::end(s), ch);
|
||||||
|
return pos != std::end(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isIgnoreWord(int ch) {
|
||||||
|
static char s[] = " \n\r\t";
|
||||||
|
auto pos = std::find(std::begin(s), std::end(s), ch);
|
||||||
|
return pos != std::end(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
Token IstreamTokenizer::get()
|
||||||
|
{
|
||||||
|
Token t;
|
||||||
|
if (is->eof()) {
|
||||||
|
t.type = ttEof;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
eatSpace();
|
||||||
|
t.line = line;
|
||||||
|
auto ch = is->peek();
|
||||||
|
if (isdigit(ch))
|
||||||
|
getNumber(t);
|
||||||
|
else if (isOperatorWord(ch))
|
||||||
|
getOperator(t);
|
||||||
|
else
|
||||||
|
getLiteral(t);
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IstreamTokenizer::getLiteral(Token & t)
|
||||||
|
{
|
||||||
|
auto ch = is->get();
|
||||||
|
t.str += ch;
|
||||||
|
while (!isCutCharactor(ch = is->peek()))
|
||||||
|
{
|
||||||
|
if (is->eof()) break;
|
||||||
|
t.str += ch;
|
||||||
|
is->get();
|
||||||
|
}
|
||||||
|
if (t.str == "end"||t.str == "else"||
|
||||||
|
t.str=="if"||t.str=="for"||t.str == "in"
|
||||||
|
||t.str =="break"||t.str=="continue"||t.str=="fn"||t.str =="return") { //임시로 해놓은 것. 나중에 바꾸자.
|
||||||
|
t.type = ttKeyword;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
t.type = ttIdentifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IstreamTokenizer::getNumber(Token & t)
|
||||||
|
{
|
||||||
|
auto ch = is->get();
|
||||||
|
t.str += ch;
|
||||||
|
while (isdigit(ch = is->peek()))
|
||||||
|
{
|
||||||
|
t.str += ch;
|
||||||
|
is->get();
|
||||||
|
}
|
||||||
|
if (is->peek() == '.') {
|
||||||
|
while (isdigit(ch = is->peek()))
|
||||||
|
{
|
||||||
|
t.str += ch;
|
||||||
|
is->get();
|
||||||
|
}
|
||||||
|
t.type = ttFloat;
|
||||||
|
}
|
||||||
|
else t.type = ttInteger;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::IstreamTokenizer::getOperator(Token & t)
|
||||||
|
{
|
||||||
|
auto ch = is->get();
|
||||||
|
t.str += ch;
|
||||||
|
while (isOperatorWord(ch = is->peek()))
|
||||||
|
{
|
||||||
|
t.str += ch;
|
||||||
|
is->get();
|
||||||
|
}
|
||||||
|
t.type = ttOperator;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IstreamTokenizer::eatSpace()
|
||||||
|
{
|
||||||
|
int ch;
|
||||||
|
while(isIgnoreWord(ch = is->peek()))
|
||||||
|
{
|
||||||
|
if (ch == '\n')
|
||||||
|
line++;
|
||||||
|
is->get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::istream & ls::operator>>(std::istream & is, Token & t)
|
||||||
|
{
|
||||||
|
IstreamTokenizer tokenizer(is);
|
||||||
|
t = tokenizer.get();
|
||||||
|
return is;
|
||||||
|
}
|
25
LightScript/Lexer.h
Normal file
25
LightScript/Lexer.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#include<istream>
|
||||||
|
#include"Token.h"
|
||||||
|
|
||||||
|
#ifndef LS_Lexer_H_
|
||||||
|
#define LS_Lexer_H_
|
||||||
|
namespace ls {
|
||||||
|
class IstreamTokenizer {
|
||||||
|
public:
|
||||||
|
explicit IstreamTokenizer(std::istream & istream)
|
||||||
|
:is(&istream){}
|
||||||
|
|
||||||
|
Token get();
|
||||||
|
private:
|
||||||
|
void getLiteral(Token &);
|
||||||
|
void getNumber(Token &);
|
||||||
|
void getOperator(Token &);
|
||||||
|
void eatSpace();
|
||||||
|
private:
|
||||||
|
std::istream * is;
|
||||||
|
int line;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::istream & operator>>(std::istream &, Token &);
|
||||||
|
}
|
||||||
|
#endif
|
145
LightScript/LightScript.vcxproj
Normal file
145
LightScript/LightScript.vcxproj
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<VCProjectVersion>15.0</VCProjectVersion>
|
||||||
|
<ProjectGuid>{99DA223F-E88F-4E97-A314-E798486955A8}</ProjectGuid>
|
||||||
|
<RootNamespace>LightScript</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="Shared">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup />
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="AST.cpp" />
|
||||||
|
<ClCompile Include="ByteCode.cpp" />
|
||||||
|
<ClCompile Include="CodeGeneration.cpp" />
|
||||||
|
<ClCompile Include="CompoundType.cpp" />
|
||||||
|
<ClCompile Include="Lexer.cpp" />
|
||||||
|
<ClCompile Include="main.cpp" />
|
||||||
|
<ClCompile Include="Operators.cpp" />
|
||||||
|
<ClCompile Include="Parser.cpp" />
|
||||||
|
<ClCompile Include="Token.cpp" />
|
||||||
|
<ClCompile Include="BoxedVar.cpp" />
|
||||||
|
<ClCompile Include="VirtualMachine.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="AST.h" />
|
||||||
|
<ClInclude Include="ByteCode.h" />
|
||||||
|
<ClInclude Include="CodeGeneration.h" />
|
||||||
|
<ClInclude Include="CompoundType.h" />
|
||||||
|
<ClInclude Include="Lexer.h" />
|
||||||
|
<ClInclude Include="BoxedVar.h" />
|
||||||
|
<ClInclude Include="LuaScriptGeneration.h" />
|
||||||
|
<ClInclude Include="Operators.h" />
|
||||||
|
<ClInclude Include="Parser.h" />
|
||||||
|
<ClInclude Include="Token.h" />
|
||||||
|
<ClInclude Include="VirtualMachine.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="aaa.ls" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
92
LightScript/LightScript.vcxproj.filters
Normal file
92
LightScript/LightScript.vcxproj.filters
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="소스 파일">
|
||||||
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||||
|
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="헤더 파일">
|
||||||
|
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||||
|
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="리소스 파일">
|
||||||
|
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||||
|
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="main.cpp">
|
||||||
|
<Filter>소스 파일</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Token.cpp">
|
||||||
|
<Filter>소스 파일</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Lexer.cpp">
|
||||||
|
<Filter>소스 파일</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="CompoundType.cpp">
|
||||||
|
<Filter>소스 파일</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Parser.cpp">
|
||||||
|
<Filter>소스 파일</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Operators.cpp">
|
||||||
|
<Filter>소스 파일</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="ByteCode.cpp">
|
||||||
|
<Filter>소스 파일</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="AST.cpp">
|
||||||
|
<Filter>소스 파일</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="CodeGeneration.cpp">
|
||||||
|
<Filter>소스 파일</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="VirtualMachine.cpp">
|
||||||
|
<Filter>소스 파일</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="BoxedVar.cpp">
|
||||||
|
<Filter>소스 파일</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="Token.h">
|
||||||
|
<Filter>헤더 파일</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Lexer.h">
|
||||||
|
<Filter>헤더 파일</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Parser.h">
|
||||||
|
<Filter>헤더 파일</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="AST.h">
|
||||||
|
<Filter>헤더 파일</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="CompoundType.h">
|
||||||
|
<Filter>헤더 파일</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Operators.h">
|
||||||
|
<Filter>헤더 파일</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="VirtualMachine.h">
|
||||||
|
<Filter>헤더 파일</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="ByteCode.h">
|
||||||
|
<Filter>헤더 파일</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="CodeGeneration.h">
|
||||||
|
<Filter>헤더 파일</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="BoxedVar.h">
|
||||||
|
<Filter>헤더 파일</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="LuaScriptGeneration.h">
|
||||||
|
<Filter>헤더 파일</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="aaa.ls">
|
||||||
|
<Filter>리소스 파일</Filter>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
11
LightScript/LightScript.vcxproj.user
Normal file
11
LightScript/LightScript.vcxproj.user
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<LocalDebuggerCommandArguments>aaa.ls --debug true --mode lua_script</LocalDebuggerCommandArguments>
|
||||||
|
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<LocalDebuggerCommandArguments>aaa.ls --debug true --mode lua_script</LocalDebuggerCommandArguments>
|
||||||
|
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
23
LightScript/LuaScriptGeneration.h
Normal file
23
LightScript/LuaScriptGeneration.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#include<sstream>
|
||||||
|
|
||||||
|
#ifndef LS_LuaScriptGeneration_H_
|
||||||
|
#define LS_LuaScriptGeneration_H_
|
||||||
|
|
||||||
|
namespace ls {
|
||||||
|
struct LuaScriptGenerateContext
|
||||||
|
{
|
||||||
|
std::ostream * outstream;
|
||||||
|
int depth = 0;
|
||||||
|
inline std::ostream & out() { return *outstream; }
|
||||||
|
inline void out(std::ostream & os) { outstream = &os; }
|
||||||
|
inline void sentence_tap() {
|
||||||
|
for (size_t i = 0; i < depth; i++)
|
||||||
|
{
|
||||||
|
out() << "\t";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
14
LightScript/Operators.cpp
Normal file
14
LightScript/Operators.cpp
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#include "Operators.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
std::string ls::to_string(Opers op)
|
||||||
|
{
|
||||||
|
static const char * const lookup[] = { "ERROR",
|
||||||
|
"and","or","not","+","-",
|
||||||
|
"+","-","*","/",
|
||||||
|
"==","!=",">",">=","<",
|
||||||
|
"<="
|
||||||
|
};
|
||||||
|
return lookup[op];
|
||||||
|
}
|
30
LightScript/Operators.h
Normal file
30
LightScript/Operators.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#include<string>
|
||||||
|
|
||||||
|
#ifndef LS_Operators_H_
|
||||||
|
#define LS_Operators_H_
|
||||||
|
namespace ls {
|
||||||
|
enum Opers
|
||||||
|
{
|
||||||
|
kERROR,
|
||||||
|
kAnd,
|
||||||
|
kOr,
|
||||||
|
kNot,
|
||||||
|
|
||||||
|
kPlus,
|
||||||
|
kMinus,
|
||||||
|
|
||||||
|
kAdd,
|
||||||
|
kSub,
|
||||||
|
kMul,
|
||||||
|
kDiv,
|
||||||
|
|
||||||
|
kEqual,
|
||||||
|
kNotEqual,
|
||||||
|
kGreater,
|
||||||
|
kEqualGreater,
|
||||||
|
kLess,
|
||||||
|
kLessEqual,
|
||||||
|
};
|
||||||
|
std::string to_string(Opers op);
|
||||||
|
}
|
||||||
|
#endif
|
447
LightScript/Parser.cpp
Normal file
447
LightScript/Parser.cpp
Normal file
@ -0,0 +1,447 @@
|
|||||||
|
#include "Parser.h"
|
||||||
|
|
||||||
|
using namespace ls;
|
||||||
|
|
||||||
|
using std::make_unique;
|
||||||
|
|
||||||
|
unique_ptr<AST_SentenceList> ls::Parser::parseSentenceList()
|
||||||
|
{
|
||||||
|
auto ret = make_unique<AST_SentenceList>();
|
||||||
|
for (;;) {
|
||||||
|
auto sentence = parseSentence();
|
||||||
|
if (sentence == nullptr)
|
||||||
|
break;
|
||||||
|
ret->push_back(move(sentence));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<AST_Sentence> ls::Parser::parseSentence()
|
||||||
|
{
|
||||||
|
unique_ptr<AST_Sentence> ret;
|
||||||
|
if (it->str == "continue") {
|
||||||
|
it++;
|
||||||
|
ret = make_unique<AST_Continue>();
|
||||||
|
}
|
||||||
|
else if (it->str == "break") {
|
||||||
|
it++;
|
||||||
|
ret = make_unique<AST_Break>();
|
||||||
|
}
|
||||||
|
else if (it->str == "var") {
|
||||||
|
ret = parseVarSentence();
|
||||||
|
}
|
||||||
|
else if (it->str == "return") {
|
||||||
|
ret = parseReturn();
|
||||||
|
}
|
||||||
|
else if (it->str == "while") {
|
||||||
|
ret = parseWhileSentence();
|
||||||
|
}
|
||||||
|
else if (it->str == "if") {
|
||||||
|
ret = parseIfSentence();
|
||||||
|
}
|
||||||
|
else if (it->str == "for") {
|
||||||
|
ret = parseForInSentence();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ret = parseCommonSentence();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<AST_Sentence> ls::Parser::parseCommonSentence()
|
||||||
|
{
|
||||||
|
unique_ptr<AST_Sentence> ret;
|
||||||
|
auto lvalue = expr();
|
||||||
|
if (lvalue == nullptr) return nullptr;
|
||||||
|
if (it->str == "=") {
|
||||||
|
it++;
|
||||||
|
auto r = expr();
|
||||||
|
return make_unique<AST_AssignmentSentence>(move(lvalue), move(r));
|
||||||
|
}
|
||||||
|
return make_unique<AST_CommonSentence>(move(lvalue));
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<AST_Sentence> ls::Parser::parseVarSentence()
|
||||||
|
{
|
||||||
|
if (it->str == "var") {
|
||||||
|
it++;
|
||||||
|
auto lv = parseIdentifier();
|
||||||
|
if (lv == nullptr)
|
||||||
|
ThrowExpected("Lvalue Expected");
|
||||||
|
if (it->str != "=")
|
||||||
|
ThrowExpected("expected symbol \'=\'");
|
||||||
|
it++;
|
||||||
|
auto r = expr();
|
||||||
|
if (r == nullptr)
|
||||||
|
ThrowExpected("Rvalue Expected");
|
||||||
|
return (make_unique<AST_VarSentence>(move(lv), move(r)));
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<AST_Sentence> ls::Parser::parseWhileSentence()
|
||||||
|
{
|
||||||
|
if (it->str == "while") {
|
||||||
|
it++;
|
||||||
|
auto lv = expr();
|
||||||
|
if (lv == nullptr)
|
||||||
|
ThrowExpected("expr Expected");
|
||||||
|
if (it->str != "do")
|
||||||
|
ThrowExpected("expected keyword \'do\'");
|
||||||
|
it++;
|
||||||
|
auto r = parseSentenceList();
|
||||||
|
if (r == nullptr)
|
||||||
|
ThrowExpected("Rvalue Expected");
|
||||||
|
if (it->str != "end")
|
||||||
|
ThrowExpected("end Expected");
|
||||||
|
it++;
|
||||||
|
return (make_unique<AST_While>(move(lv), move(r)));
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<AST_Sentence> ls::Parser::parseIfSentence()
|
||||||
|
{
|
||||||
|
if (it->str == "if") {
|
||||||
|
it++;
|
||||||
|
auto lv = expr();
|
||||||
|
if (lv == nullptr)
|
||||||
|
ThrowExpected("expr Expected");
|
||||||
|
if (it->str != "then")
|
||||||
|
ThrowExpected("expected keyword \'then\'");
|
||||||
|
it++;
|
||||||
|
auto r = parseSentenceList();
|
||||||
|
if (r == nullptr)
|
||||||
|
ThrowExpected("Rvalue Expected");
|
||||||
|
auto ret = (make_unique<AST_If>(move(lv), move(r)));
|
||||||
|
if (it->str == "else") {
|
||||||
|
it++;
|
||||||
|
auto elsec = parseSentenceList();
|
||||||
|
if (elsec == nullptr)
|
||||||
|
ThrowExpected("expected Sentence next to else");
|
||||||
|
ret->setElse(move(elsec));
|
||||||
|
}
|
||||||
|
if (it->str != "end")
|
||||||
|
ThrowExpected("end Expected");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<AST_Sentence> ls::Parser::parseForInSentence()
|
||||||
|
{
|
||||||
|
if (it->str == "for") {
|
||||||
|
it++;
|
||||||
|
auto id = parseIdentifier();
|
||||||
|
if (id == nullptr) {
|
||||||
|
ThrowExpected("expected identifier");
|
||||||
|
}
|
||||||
|
if (it->str != "in")
|
||||||
|
ThrowExpected("expected keyword \'in\'");
|
||||||
|
it++;
|
||||||
|
auto lv = expr();
|
||||||
|
if (lv == nullptr)
|
||||||
|
ThrowExpected("expr Expected");
|
||||||
|
if (it->str != "do")
|
||||||
|
ThrowExpected("expected keyword \'do\'");
|
||||||
|
it++;
|
||||||
|
auto sl = parseSentenceList();
|
||||||
|
if (sl == nullptr)
|
||||||
|
ThrowExpected("Rvalue Expected");
|
||||||
|
if (it->str != "end")
|
||||||
|
ThrowExpected("end Expected");
|
||||||
|
return make_unique<AST_ForIn>(move(id), move(lv), move(sl));
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<AST_Sentence> ls::Parser::parseReturn()
|
||||||
|
{
|
||||||
|
if (it->str == "return") {
|
||||||
|
it++;
|
||||||
|
auto retValue = expr();
|
||||||
|
if (retValue != nullptr)
|
||||||
|
return make_unique<AST_Return>(move(retValue));
|
||||||
|
else
|
||||||
|
return make_unique<AST_Return>(make_unique<AST_None>());
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<AST_Expr> Parser::parseLogicalBinary()
|
||||||
|
{
|
||||||
|
unique_ptr<AST_Expr> LHS, RHS;
|
||||||
|
LHS = parseLogicalUnary();
|
||||||
|
if (LHS == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
while (it->str == "and" || it->str == "or") {
|
||||||
|
auto op = it->str;
|
||||||
|
it++;
|
||||||
|
RHS = parseLogicalUnary();
|
||||||
|
if (RHS == nullptr)
|
||||||
|
ThrowExpected("Expected Expression");
|
||||||
|
if (op == "and")
|
||||||
|
LHS = make_unique<AST_Binary>(kAnd,move(LHS), move(RHS));
|
||||||
|
else if (op == "or")
|
||||||
|
LHS = make_unique<AST_Binary>(kOr,move(LHS), move(RHS));
|
||||||
|
}
|
||||||
|
return LHS;
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<AST_Expr> ls::Parser::parseLogicalUnary()
|
||||||
|
{
|
||||||
|
if (it->str == "not") {
|
||||||
|
++it;
|
||||||
|
auto ret = parseComparison();
|
||||||
|
if (ret == nullptr)
|
||||||
|
ThrowExpected("Expected Expression");
|
||||||
|
return make_unique<AST_Unary>(kNot,move(ret));
|
||||||
|
}
|
||||||
|
return parseComparison();
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<AST_Expr> ls::Parser::parseComparison()
|
||||||
|
{
|
||||||
|
unique_ptr<AST_Expr> LHS, RHS;
|
||||||
|
LHS = parseAddAndSub();
|
||||||
|
if (LHS == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
while (it->str == "=="||
|
||||||
|
it->str == "!="||
|
||||||
|
it->str == "<"||
|
||||||
|
it->str == "<="||
|
||||||
|
it->str == ">"||
|
||||||
|
it->str == ">=") {
|
||||||
|
auto op = it->str;
|
||||||
|
++it;
|
||||||
|
RHS = parseAddAndSub();
|
||||||
|
if (RHS == nullptr)
|
||||||
|
ThrowExpected("Expected Expression");
|
||||||
|
if (op == "==")
|
||||||
|
LHS = make_unique<AST_Binary>(kEqual, move(LHS), move(RHS));
|
||||||
|
else if (op == "!=")
|
||||||
|
LHS = make_unique<AST_Binary>(kNotEqual, move(LHS), move(RHS));
|
||||||
|
else if (op == ">")
|
||||||
|
LHS = make_unique<AST_Binary>(kGreater, move(LHS), move(RHS));
|
||||||
|
else if (op == ">=")
|
||||||
|
LHS = make_unique<AST_Binary>(kEqualGreater, move(LHS), move(RHS));
|
||||||
|
else if (op == "<")
|
||||||
|
LHS = make_unique<AST_Binary>(kLess, move(LHS), move(RHS));
|
||||||
|
else if (op == "<=")
|
||||||
|
LHS = make_unique<AST_Binary>(kLessEqual, move(LHS), move(RHS));
|
||||||
|
}
|
||||||
|
return LHS;
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<AST_Expr> ls::Parser::parseAddAndSub() //code ¸®ÆåÅ丵 ÇÒ °÷.
|
||||||
|
{
|
||||||
|
unique_ptr<AST_Expr> LHS, RHS;
|
||||||
|
if (it->str == "+") {
|
||||||
|
++it;
|
||||||
|
LHS = parseMulAndDiv();
|
||||||
|
if (LHS == nullptr)
|
||||||
|
ThrowExpected("Expected Expression");
|
||||||
|
LHS = make_unique<AST_Unary>(kPlus,move(LHS));
|
||||||
|
}
|
||||||
|
else if (it->str == "-") {
|
||||||
|
++it;
|
||||||
|
LHS = parseMulAndDiv();
|
||||||
|
if (LHS == nullptr)
|
||||||
|
ThrowExpected("Expected Expression");
|
||||||
|
LHS = make_unique<AST_Unary>(kMinus,move(LHS));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LHS = parseMulAndDiv();
|
||||||
|
}
|
||||||
|
if (LHS == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
while (it->str == "+" || it->str == "-") {
|
||||||
|
auto op = it->str;
|
||||||
|
++it;
|
||||||
|
RHS = parseMulAndDiv();
|
||||||
|
if (RHS == nullptr)
|
||||||
|
ThrowExpected("Expected Expression");
|
||||||
|
if (op == "+")
|
||||||
|
LHS = make_unique<AST_Binary>(kAdd,move(LHS), move(RHS));
|
||||||
|
else if (op == "-")
|
||||||
|
LHS = make_unique<AST_Binary>(kSub,move(LHS), move(RHS));
|
||||||
|
}
|
||||||
|
return LHS;
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<AST_Expr> ls::Parser::parseMulAndDiv()
|
||||||
|
{
|
||||||
|
unique_ptr<AST_Expr> LHS, RHS;
|
||||||
|
LHS = parseAttrAccess();
|
||||||
|
if (LHS == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
while (it->str == "*" || it->str == "/") {
|
||||||
|
auto op = it->str;
|
||||||
|
++it;
|
||||||
|
RHS = parseAttrAccess();
|
||||||
|
if (RHS == nullptr)
|
||||||
|
ThrowExpected("Expected Expression");
|
||||||
|
if (op == "*")
|
||||||
|
LHS = make_unique<AST_Binary>(kMul,move(LHS), move(RHS));
|
||||||
|
else if (op == "/")
|
||||||
|
LHS = make_unique<AST_Binary>(kDiv,move(LHS), move(RHS));
|
||||||
|
}
|
||||||
|
return LHS;
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<AST_Expr> ls::Parser::parseAttrAccess()
|
||||||
|
{
|
||||||
|
unique_ptr<AST_Expr> LHS;
|
||||||
|
LHS = parsePrimary();
|
||||||
|
if (LHS == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
for(;;){
|
||||||
|
if (it->str == "[") {
|
||||||
|
++it;
|
||||||
|
auto RHS = expr();
|
||||||
|
if (RHS == nullptr)
|
||||||
|
ThrowExpected("Expected Expression");
|
||||||
|
if (it->str != "]")
|
||||||
|
ThrowExpected("Expected \')\'");
|
||||||
|
it++;
|
||||||
|
LHS = make_unique<AST_Index>(move(LHS), move(RHS));
|
||||||
|
}
|
||||||
|
else if (it->str == ".") {
|
||||||
|
it++;
|
||||||
|
auto RHS = parseIdentifier();
|
||||||
|
LHS = make_unique<AST_Dot>(move(LHS), move(RHS));
|
||||||
|
}
|
||||||
|
else if (it->str == "(") {
|
||||||
|
++it;
|
||||||
|
auto L = make_unique<AST_CallExpr>(move(LHS));
|
||||||
|
if (it->str != ")")
|
||||||
|
{
|
||||||
|
auto RHS = expr();
|
||||||
|
if (RHS == nullptr) {
|
||||||
|
ThrowExpected("Expected expression.");
|
||||||
|
}
|
||||||
|
L->push_back(move(RHS));
|
||||||
|
while (it->str != ")") {
|
||||||
|
if (it->str != ",") {
|
||||||
|
ThrowExpected("Expected \',\'");
|
||||||
|
}
|
||||||
|
it++;
|
||||||
|
RHS = expr();
|
||||||
|
if (RHS == nullptr)
|
||||||
|
ThrowExpected("Expected expression.");
|
||||||
|
L->push_back(move(RHS));
|
||||||
|
}
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
LHS = move(L);
|
||||||
|
}
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
return LHS;
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<AST_Expr> ls::Parser::parsePrimary()
|
||||||
|
{
|
||||||
|
if (it->str == "(")
|
||||||
|
{
|
||||||
|
it++;
|
||||||
|
auto ret = expr();
|
||||||
|
if (ret == nullptr) {
|
||||||
|
ThrowExpected("expected expression");
|
||||||
|
}
|
||||||
|
if (it->str != ")") {
|
||||||
|
ThrowExpected("expected \')\'");
|
||||||
|
}
|
||||||
|
it++;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
else if (it->type == ttIdentifier) {
|
||||||
|
return parseIdentifier();
|
||||||
|
}
|
||||||
|
return parseLiteral();
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<AST_Expr> ls::Parser::parseLiteral()
|
||||||
|
{
|
||||||
|
if (it->type == ls::TokenType::ttInteger) {
|
||||||
|
return parseInteger();
|
||||||
|
}
|
||||||
|
else if (it->type == ttFloat) {
|
||||||
|
return parseFloating();
|
||||||
|
}
|
||||||
|
else if (it->str == "fn") {
|
||||||
|
return parseFunction();
|
||||||
|
}
|
||||||
|
else if (it->str == "{") {
|
||||||
|
return parseTableExpr();
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<AST_Expr> Parser::parseInteger()
|
||||||
|
{
|
||||||
|
if (it->type != TokenType::ttInteger)
|
||||||
|
return nullptr;
|
||||||
|
auto value = std::stoll(it->str);
|
||||||
|
it++;
|
||||||
|
return make_unique<AST_Int>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<AST_Expr> Parser::parseFloating()
|
||||||
|
{
|
||||||
|
if (it->type != TokenType::ttFloat)
|
||||||
|
return nullptr;
|
||||||
|
auto value = std::stod(it->str);
|
||||||
|
it++;
|
||||||
|
return make_unique<AST_Float>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<AST_Expr> ls::Parser::parseFunction()
|
||||||
|
{
|
||||||
|
if (it->str != "fn")
|
||||||
|
return nullptr;
|
||||||
|
it++;
|
||||||
|
if (it->str != "(")
|
||||||
|
ThrowExpected("expected \'(\'");
|
||||||
|
auto L = make_unique<AST_Function>();
|
||||||
|
it++;
|
||||||
|
if (it->str != ")")
|
||||||
|
{
|
||||||
|
auto Id = parseIdentifier();
|
||||||
|
if (Id == nullptr) {
|
||||||
|
ThrowExpected("Expected Identifier.");
|
||||||
|
}
|
||||||
|
L->push_back(move(Id));
|
||||||
|
while (it->str != ")") {
|
||||||
|
if (it->str != ",") {
|
||||||
|
ThrowExpected("Expected \',\'");
|
||||||
|
}
|
||||||
|
it++;
|
||||||
|
Id = parseIdentifier();
|
||||||
|
if (Id == nullptr)
|
||||||
|
ThrowExpected("Expected Identifier.");
|
||||||
|
L->push_back(move(Id));
|
||||||
|
}
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
L->setSentenceList(parseSentenceList());
|
||||||
|
if (it->str != "end")
|
||||||
|
ThrowExpected("expected \'end\'");
|
||||||
|
it++;
|
||||||
|
return L;
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<AST_Expr> ls::Parser::parseTableExpr()
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<AST_Ident> ls::Parser::parseIdentifier()
|
||||||
|
{
|
||||||
|
if (it->type == ttIdentifier) {
|
||||||
|
auto ret = make_unique<AST_Ident>(it->str);
|
||||||
|
it++;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
75
LightScript/Parser.h
Normal file
75
LightScript/Parser.h
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
|
||||||
|
#include<memory>
|
||||||
|
|
||||||
|
#include<list>
|
||||||
|
#include<exception>
|
||||||
|
#include"Token.h"
|
||||||
|
#include"AST.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef LS_Parser_H_
|
||||||
|
#define LS_Parser_H_
|
||||||
|
namespace ls {
|
||||||
|
typedef std::list<Token> Container;
|
||||||
|
typedef Container::const_iterator Tokit;
|
||||||
|
|
||||||
|
class ExpectedException : public std::exception {
|
||||||
|
public:
|
||||||
|
ExpectedException(const char * const message, int l)
|
||||||
|
:std::exception(message), line(l) {}
|
||||||
|
|
||||||
|
int line;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
using std::unique_ptr;
|
||||||
|
class Parser {
|
||||||
|
public:
|
||||||
|
inline void ThrowExpected(const char * const message) {
|
||||||
|
throw ExpectedException(message, it->line);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(Tokit begin) { it = begin; }
|
||||||
|
unique_ptr<AST_SentenceList> parseSentenceList();
|
||||||
|
unique_ptr<AST_Sentence> parseSentence();
|
||||||
|
inline unique_ptr<AST_Expr> expr() { return parseLogicalBinary(); }
|
||||||
|
private:
|
||||||
|
unique_ptr<AST_Sentence> parseCommonSentence();
|
||||||
|
unique_ptr<AST_Sentence> parseVarSentence();
|
||||||
|
unique_ptr<AST_Sentence> parseWhileSentence();
|
||||||
|
unique_ptr<AST_Sentence> parseIfSentence();
|
||||||
|
unique_ptr<AST_Sentence> parseForInSentence();
|
||||||
|
unique_ptr<AST_Sentence> parseReturn();
|
||||||
|
private:
|
||||||
|
//<LogicalBinary> := <LogicalUnary>{("and"|"or")-<LogicalUnary>}
|
||||||
|
unique_ptr<AST_Expr> parseLogicalBinary();
|
||||||
|
//<LogicalUnary> := ["not"]<Comparison>
|
||||||
|
unique_ptr<AST_Expr> parseLogicalUnary();
|
||||||
|
//<Comparison> := <AddAndSub>{("=="|"!="|"<="|"<"|">="|">")-<AddAndSub>}
|
||||||
|
unique_ptr<AST_Expr> parseComparison();
|
||||||
|
//<AddAndSub> := ["+"|"-"]<MulAndDiv>{("+"|"-")-<MulAndDiv>}
|
||||||
|
unique_ptr<AST_Expr> parseAddAndSub();
|
||||||
|
//<MulAndDiv> := <AttrAccess>{("*"|"/")-<AttrAccess>}
|
||||||
|
unique_ptr<AST_Expr> parseMulAndDiv();
|
||||||
|
//<AttrAccess> := <PrimaryExpr>{("["-<expr>-"]")|("("-([<Expr>],{","-<Expr>})-")")|"."<Identifer>}
|
||||||
|
unique_ptr<AST_Expr> parseAttrAccess();
|
||||||
|
//<Primary> := "("-<expr>-")"|<Identifier>|<Literal>
|
||||||
|
unique_ptr<AST_Expr> parsePrimary();
|
||||||
|
//<Literal> := <Interger>|<Floating>|<String>|<Table>|<Function>
|
||||||
|
unique_ptr<AST_Expr> parseLiteral();
|
||||||
|
unique_ptr<AST_Expr> parseInteger();
|
||||||
|
unique_ptr<AST_Expr> parseFloating();
|
||||||
|
unique_ptr<AST_Expr> parseFunction();
|
||||||
|
//¿Ï¼º ¾ÈµÊ.
|
||||||
|
unique_ptr<AST_Expr> parseTableExpr();
|
||||||
|
|
||||||
|
unique_ptr<AST_Ident> parseIdentifier();
|
||||||
|
|
||||||
|
//unique_ptr<AST_Expr> level6()
|
||||||
|
private:
|
||||||
|
Tokit it;
|
||||||
|
Tokit end;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
20
LightScript/Token.cpp
Normal file
20
LightScript/Token.cpp
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include "Token.h"
|
||||||
|
|
||||||
|
|
||||||
|
const char * ls::keyword_list[20] = { "if","else","elif","fn","for","in","while","loop","end","then" };
|
||||||
|
static const char * token_type_list[] = {"eof","op",
|
||||||
|
"int",
|
||||||
|
"kwrd",
|
||||||
|
"float",
|
||||||
|
"str",
|
||||||
|
"ident",
|
||||||
|
"hex",
|
||||||
|
};
|
||||||
|
|
||||||
|
std::ostream & ls::operator<<(std::ostream & os, const Token & tk)
|
||||||
|
{
|
||||||
|
os <<"[" << tk.str<<",";
|
||||||
|
os << token_type_list[tk.type]<<"]";
|
||||||
|
return os;
|
||||||
|
}
|
37
LightScript/Token.h
Normal file
37
LightScript/Token.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include<string>
|
||||||
|
#include<ostream>
|
||||||
|
#ifndef LS_Token_H_
|
||||||
|
#define LS_Token_H_
|
||||||
|
//#ifndef _LS_Token_H_
|
||||||
|
//#define _LS_Token_H_
|
||||||
|
|
||||||
|
namespace ls {
|
||||||
|
|
||||||
|
enum TokenType
|
||||||
|
{
|
||||||
|
ttEof,
|
||||||
|
ttOperator,
|
||||||
|
ttInteger,
|
||||||
|
ttKeyword,
|
||||||
|
ttFloat,
|
||||||
|
ttString,
|
||||||
|
ttIdentifier,
|
||||||
|
ttHexnumber,
|
||||||
|
};
|
||||||
|
struct Token
|
||||||
|
{
|
||||||
|
TokenType type;
|
||||||
|
int line;
|
||||||
|
std::string str;
|
||||||
|
|
||||||
|
Token():type(ttEof),line(0)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const char * keyword_list[20];
|
||||||
|
|
||||||
|
std::ostream & operator<<(std::ostream & os, const Token & tk);
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endif
|
||||||
|
#endif
|
435
LightScript/VirtualMachine.cpp
Normal file
435
LightScript/VirtualMachine.cpp
Normal file
@ -0,0 +1,435 @@
|
|||||||
|
#include "VirtualMachine.h"
|
||||||
|
|
||||||
|
using namespace ls;
|
||||||
|
|
||||||
|
bool ls::VirtualMachine::runOneCode()
|
||||||
|
{
|
||||||
|
if (programCounter>=programFrameEnd) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
switch (programFrame->code[programCounter].code)
|
||||||
|
{
|
||||||
|
case code_t::nop:
|
||||||
|
break;
|
||||||
|
case code_t::add:
|
||||||
|
add();
|
||||||
|
break;
|
||||||
|
case code_t::enterScope:
|
||||||
|
enterScope();
|
||||||
|
break;
|
||||||
|
case code_t::leaveScope:
|
||||||
|
leaveScope();
|
||||||
|
break;
|
||||||
|
case code_t::load:
|
||||||
|
load();
|
||||||
|
break;
|
||||||
|
case code_t::and:
|
||||||
|
and();
|
||||||
|
break;
|
||||||
|
case code_t::or:
|
||||||
|
or();
|
||||||
|
break;
|
||||||
|
case code_t::not:
|
||||||
|
not();
|
||||||
|
break;
|
||||||
|
case code_t::sub:
|
||||||
|
sub();
|
||||||
|
break;
|
||||||
|
case code_t::mul:
|
||||||
|
mul();
|
||||||
|
break;
|
||||||
|
case code_t::div:
|
||||||
|
div();
|
||||||
|
break;
|
||||||
|
case code_t::plus:
|
||||||
|
plus();
|
||||||
|
break;
|
||||||
|
case code_t::minus:
|
||||||
|
minus();
|
||||||
|
break;
|
||||||
|
case code_t::eq:
|
||||||
|
eq();
|
||||||
|
break;
|
||||||
|
case code_t::neq:
|
||||||
|
neq();
|
||||||
|
break;
|
||||||
|
case code_t::gt:
|
||||||
|
gt();
|
||||||
|
break;
|
||||||
|
case code_t::gte:
|
||||||
|
gte();
|
||||||
|
break;
|
||||||
|
case code_t::less:
|
||||||
|
less();
|
||||||
|
break;
|
||||||
|
case code_t::leq:
|
||||||
|
leq();
|
||||||
|
break;
|
||||||
|
case code_t::push:
|
||||||
|
push();
|
||||||
|
break;
|
||||||
|
case code_t::pop:
|
||||||
|
pop();
|
||||||
|
break;
|
||||||
|
case code_t::store:
|
||||||
|
store();
|
||||||
|
break;
|
||||||
|
case code_t::new_var:
|
||||||
|
new_var();
|
||||||
|
break;
|
||||||
|
case code_t::jmp:
|
||||||
|
jmp();
|
||||||
|
break;
|
||||||
|
case code_t::jt:
|
||||||
|
jt();
|
||||||
|
break;
|
||||||
|
case code_t::jf:
|
||||||
|
jf();
|
||||||
|
break;
|
||||||
|
case code_t::call:
|
||||||
|
call();
|
||||||
|
break;
|
||||||
|
case code_t::ref:
|
||||||
|
ref();
|
||||||
|
break;
|
||||||
|
case code_t::ret:
|
||||||
|
inst_ret();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("Invailed op code.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
programCounter++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BoxedVar & ls::VirtualMachine::searchVar(const std::string & str)
|
||||||
|
{
|
||||||
|
for (auto it = variableMap.rbegin(), E = variableMap.rend(); it != E; it++) {
|
||||||
|
auto f = it->find(str);
|
||||||
|
if(f != it->end()){
|
||||||
|
return f->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw std::runtime_error("Unknown Variable");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::VirtualMachine::enterScope()
|
||||||
|
{
|
||||||
|
variableMap.emplace_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::VirtualMachine::leaveScope()
|
||||||
|
{
|
||||||
|
variableMap.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::VirtualMachine::add()
|
||||||
|
{
|
||||||
|
auto LHS = popValue();
|
||||||
|
auto RHS = popValue();
|
||||||
|
TempVariable tmp;
|
||||||
|
tmp.val()->set(LHS.get()->binaryGo(Opers::kAdd, RHS.get()));
|
||||||
|
pushValue(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::VirtualMachine::load()
|
||||||
|
{
|
||||||
|
auto str = popValue();
|
||||||
|
if (str.get()->Type() != kString) {
|
||||||
|
throw std::runtime_error("Load Failed!");
|
||||||
|
}
|
||||||
|
TempVariable t(&searchVar(static_cast<StringType *>(str.get())->value));
|
||||||
|
pushValue(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::VirtualMachine::sub()
|
||||||
|
{
|
||||||
|
auto LHS = popValue();
|
||||||
|
auto RHS = popValue();
|
||||||
|
TempVariable tmp;
|
||||||
|
tmp.val()->set(LHS.get()->binaryGo(Opers::kSub, RHS.get()));
|
||||||
|
pushValue(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::VirtualMachine::mul()
|
||||||
|
{
|
||||||
|
auto LHS = popValue();
|
||||||
|
auto RHS = popValue();
|
||||||
|
TempVariable tmp;
|
||||||
|
tmp.val()->set(LHS.get()->binaryGo(Opers::kMul, RHS.get()));
|
||||||
|
pushValue(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::VirtualMachine::div()
|
||||||
|
{
|
||||||
|
auto LHS = popValue();
|
||||||
|
auto RHS = popValue();
|
||||||
|
TempVariable tmp;
|
||||||
|
tmp.val()->set(LHS.get()->binaryGo(Opers::kDiv, RHS.get()));
|
||||||
|
pushValue(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::VirtualMachine::plus()
|
||||||
|
{
|
||||||
|
auto LHS = popValue();
|
||||||
|
TempVariable tmp;
|
||||||
|
tmp.val()->set(LHS.get()->unaryGo(Opers::kPlus));
|
||||||
|
pushValue(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::VirtualMachine::minus()
|
||||||
|
{
|
||||||
|
auto LHS = popValue();
|
||||||
|
TempVariable tmp;
|
||||||
|
tmp.val()->set(LHS.get()->unaryGo(Opers::kMinus));
|
||||||
|
pushValue(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ls::VirtualMachine::eq()
|
||||||
|
{
|
||||||
|
auto LHS = popValue();
|
||||||
|
auto RHS = popValue();
|
||||||
|
TempVariable tmp;
|
||||||
|
tmp.val()->set(LHS.get()->binaryGo(Opers::kEqual, RHS.get()));
|
||||||
|
pushValue(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::VirtualMachine::gt()
|
||||||
|
{
|
||||||
|
auto LHS = popValue();
|
||||||
|
auto RHS = popValue();
|
||||||
|
TempVariable tmp;
|
||||||
|
tmp.val()->set(LHS.get()->binaryGo(Opers::kGreater, RHS.get()));
|
||||||
|
pushValue(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::VirtualMachine::gte()
|
||||||
|
{
|
||||||
|
auto LHS = popValue();
|
||||||
|
auto RHS = popValue();
|
||||||
|
TempVariable tmp;
|
||||||
|
tmp.val()->set(LHS.get()->binaryGo(Opers::kEqualGreater, RHS.get()));
|
||||||
|
pushValue(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::VirtualMachine::less()
|
||||||
|
{
|
||||||
|
auto LHS = popValue();
|
||||||
|
auto RHS = popValue();
|
||||||
|
TempVariable tmp;
|
||||||
|
tmp.val()->set(LHS.get()->binaryGo(Opers::kLess, RHS.get()));
|
||||||
|
pushValue(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::VirtualMachine::leq()
|
||||||
|
{
|
||||||
|
auto LHS = popValue();
|
||||||
|
auto RHS = popValue();
|
||||||
|
TempVariable tmp;
|
||||||
|
tmp.val()->set(LHS.get()->binaryGo(Opers::kLessEqual, RHS.get()));
|
||||||
|
pushValue(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::VirtualMachine::neq()
|
||||||
|
{
|
||||||
|
auto LHS = popValue();
|
||||||
|
auto RHS = popValue();
|
||||||
|
TempVariable tmp;
|
||||||
|
tmp.val()->set(LHS.get()->binaryGo(Opers::kNotEqual, RHS.get()));
|
||||||
|
pushValue(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::VirtualMachine::new_var()
|
||||||
|
{
|
||||||
|
auto lst = popValue();
|
||||||
|
auto rst = popValue();
|
||||||
|
if (lst.get()->Type() != kString)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("변수이름은 문자열이어야 합니다.");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto name = static_cast<StringType *>(lst.get())->value;
|
||||||
|
auto pos = variableMap.back().find(name);
|
||||||
|
if (pos != variableMap.back().end()) {
|
||||||
|
throw std::runtime_error("이미 선언된 변수.");
|
||||||
|
}
|
||||||
|
variableMap.back().emplace(name, *rst.val());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::VirtualMachine::jmp()
|
||||||
|
{
|
||||||
|
auto st = popValue();
|
||||||
|
auto s = st.cast<IntegerType>(kInteger);
|
||||||
|
programCounter += s->value;
|
||||||
|
programCounter--;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::VirtualMachine::jt()
|
||||||
|
{
|
||||||
|
auto jmp_count = popValue();
|
||||||
|
auto condition = popValue();
|
||||||
|
auto jmp = jmp_count.cast<IntegerType>(kInteger);
|
||||||
|
auto cond = condition.cast<BooleanType>(kBoolean);
|
||||||
|
if (cond->value) {
|
||||||
|
programCounter += jmp->value;
|
||||||
|
programCounter--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::VirtualMachine::jf()
|
||||||
|
{
|
||||||
|
auto jmp_count = popValue();
|
||||||
|
auto condition = popValue();
|
||||||
|
auto jmp = jmp_count.cast<IntegerType>(kInteger);
|
||||||
|
auto cond = condition.cast<BooleanType>(kBoolean);
|
||||||
|
if (!cond->value) {
|
||||||
|
programCounter += jmp->value;
|
||||||
|
programCounter--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::VirtualMachine::store()
|
||||||
|
{
|
||||||
|
auto fvar = popValue();//LHS=RHS
|
||||||
|
auto lvar = popValue();
|
||||||
|
*fvar.val() = *lvar.val();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::VirtualMachine::and()
|
||||||
|
{
|
||||||
|
auto LHS = popValue();
|
||||||
|
auto RHS = popValue();
|
||||||
|
TempVariable tmp;
|
||||||
|
tmp.val()->set(LHS.get()->binaryGo(Opers::kAnd, LHS.get()));
|
||||||
|
pushValue(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::VirtualMachine::or()
|
||||||
|
{
|
||||||
|
auto LHS = popValue();
|
||||||
|
auto RHS = popValue();
|
||||||
|
TempVariable tmp;
|
||||||
|
tmp.val()->set(LHS.get()->binaryGo(Opers::kOr, RHS.get()));
|
||||||
|
pushValue(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::VirtualMachine::not()
|
||||||
|
{
|
||||||
|
auto LHS = popValue();
|
||||||
|
TempVariable tmp;
|
||||||
|
tmp.val()->set(LHS.get()->unaryGo(Opers::kNot));
|
||||||
|
pushValue(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::VirtualMachine::pop()
|
||||||
|
{
|
||||||
|
popValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::VirtualMachine::push()
|
||||||
|
{
|
||||||
|
TempVariable tmp;
|
||||||
|
tmp.setval(&programFrame->operands[programFrame->code[programCounter].pos]);
|
||||||
|
pushValue(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::VirtualMachine::inst_ret()
|
||||||
|
{
|
||||||
|
if (callstack.size() == 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Call Stack Error");
|
||||||
|
}
|
||||||
|
stack.back().copyTemp();
|
||||||
|
auto b = callstack.back();
|
||||||
|
programFrame = b.frame;
|
||||||
|
programFrameEnd = b.frame->code.size();
|
||||||
|
programCounter = b.address;
|
||||||
|
callstack.pop_back();
|
||||||
|
leaveScope();
|
||||||
|
programCounter--;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::VirtualMachine::next()
|
||||||
|
{
|
||||||
|
auto LHS = popValue();
|
||||||
|
bool vailed = LHS.get()->next();
|
||||||
|
if (!vailed) {
|
||||||
|
throw std::runtime_error("Type not able to iterate");
|
||||||
|
}
|
||||||
|
pushValue(LHS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::VirtualMachine::getvalue()
|
||||||
|
{
|
||||||
|
auto LHS = popValue();
|
||||||
|
auto t = LHS.cast<TableIterType>(kTableIter);
|
||||||
|
TempVariable tmp;
|
||||||
|
tmp.val()->set(t->value());
|
||||||
|
pushValue(LHS);
|
||||||
|
pushValue(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::VirtualMachine::isEnd()
|
||||||
|
{
|
||||||
|
auto LHS = popValue();
|
||||||
|
auto t = LHS.cast<TableIterType>(kTableIter);
|
||||||
|
TempVariable tmp;
|
||||||
|
tmp.val()->set(createVar(t->isEnd()));
|
||||||
|
pushValue(LHS);
|
||||||
|
pushValue(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::VirtualMachine::getiter()
|
||||||
|
{
|
||||||
|
auto LHS = popValue();
|
||||||
|
auto table = LHS.cast<TableType>(kTable);
|
||||||
|
TempVariable tmp;
|
||||||
|
tmp.val()->set(table->getiter());
|
||||||
|
pushValue(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::VirtualMachine::call()
|
||||||
|
{
|
||||||
|
auto f = popValue();
|
||||||
|
switch (f.get()->Type()) {
|
||||||
|
case kFunctionProxy:
|
||||||
|
{
|
||||||
|
auto fn = static_cast<FunctionProxyType *>(f.get());
|
||||||
|
auto arg_numT = popValue();
|
||||||
|
auto arg_num = arg_numT.cast<IntegerType>(kInteger);
|
||||||
|
std::vector<BoxedVar> C_stack;
|
||||||
|
for (size_t i = 0,endnum = arg_num->value; i < endnum; i++)
|
||||||
|
{
|
||||||
|
auto tmp = popValue();
|
||||||
|
C_stack.push_back(*tmp.val());
|
||||||
|
}
|
||||||
|
auto ret = TempVariable();
|
||||||
|
ret.val()->set(fn->call(C_stack));
|
||||||
|
pushValue(ret);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case kFunction:
|
||||||
|
{
|
||||||
|
auto fn = static_cast<FunctionType *>(f.get());
|
||||||
|
callstack.push_back({ programFrame,programCounter+1 });
|
||||||
|
programFrame = fn->code.get();
|
||||||
|
programFrameEnd = programFrame->code.size();
|
||||||
|
programCounter = -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
unexpected();//
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls::VirtualMachine::ref()
|
||||||
|
{
|
||||||
|
auto LHS = popValue();
|
||||||
|
auto RHS = popValue();
|
||||||
|
TempVariable tmp;
|
||||||
|
tmp.setval(LHS.get()->index(RHS.get()));
|
||||||
|
pushValue(tmp);
|
||||||
|
}
|
126
LightScript/VirtualMachine.h
Normal file
126
LightScript/VirtualMachine.h
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
#include<memory>
|
||||||
|
#include<unordered_map>
|
||||||
|
#include<string>
|
||||||
|
#include"ByteCode.h"
|
||||||
|
#include"BoxedVar.h"
|
||||||
|
|
||||||
|
#ifndef LS_VirtualMachine_H_
|
||||||
|
#define LS_VirtualMachine_H_
|
||||||
|
namespace ls {
|
||||||
|
//아름답지 못한 꼼수. 나중에 최적화 할 수 있는데로 해보겠음.
|
||||||
|
struct TempVariable{
|
||||||
|
private:
|
||||||
|
BoxedVar * value;
|
||||||
|
BoxedVar temp;
|
||||||
|
public:
|
||||||
|
explicit TempVariable() :value(nullptr) {}
|
||||||
|
explicit TempVariable(BoxedVar * ptr) :value(ptr) {}
|
||||||
|
TempVariable(const TempVariable & rhs)
|
||||||
|
:value(rhs.value), temp(rhs.temp) {
|
||||||
|
}
|
||||||
|
inline BoxedVar * val() {
|
||||||
|
if (nullptr == value) return &temp;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
inline CompoundType * get() {
|
||||||
|
return val()->get().get();
|
||||||
|
}
|
||||||
|
inline void setval(BoxedVar * ptr) { value = ptr;}
|
||||||
|
inline void copyTemp() {
|
||||||
|
temp = *value;
|
||||||
|
value = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ty>
|
||||||
|
Ty * cast(TypeKind t) {
|
||||||
|
auto ret = get();
|
||||||
|
if (ret->Type() != t)
|
||||||
|
throw std::exception("Invaild Type Casting Error!");
|
||||||
|
return static_cast<Ty *>(ret);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
class VirtualMachine {
|
||||||
|
public:
|
||||||
|
VirtualMachine(){
|
||||||
|
std::unordered_map<std::string, BoxedVar> t;
|
||||||
|
variableMap.push_back(t);
|
||||||
|
}
|
||||||
|
//보안적으로 위험함. 메모리 위험.
|
||||||
|
void set(FunctionCode * ic) { instcodes = ic;
|
||||||
|
programFrame = ic;
|
||||||
|
programFrameEnd = ic->code.size();
|
||||||
|
programCounter = 0;
|
||||||
|
}
|
||||||
|
bool runOneCode();
|
||||||
|
|
||||||
|
BoxedVar & searchVar(const std::string & str);
|
||||||
|
BoxedVar & setVar(const std::string & str) { return variableMap.back()[str]; }
|
||||||
|
private:
|
||||||
|
void enterScope();
|
||||||
|
void leaveScope();
|
||||||
|
|
||||||
|
void add();
|
||||||
|
void sub();
|
||||||
|
void mul();
|
||||||
|
void div();
|
||||||
|
|
||||||
|
void plus();
|
||||||
|
void minus();
|
||||||
|
|
||||||
|
void eq();
|
||||||
|
void neq();
|
||||||
|
void gt();
|
||||||
|
void gte();
|
||||||
|
void less();
|
||||||
|
void leq();
|
||||||
|
|
||||||
|
void store();
|
||||||
|
void new_var();
|
||||||
|
void jmp();
|
||||||
|
void jt();
|
||||||
|
void jf();
|
||||||
|
void call();
|
||||||
|
void ref();
|
||||||
|
|
||||||
|
void load();
|
||||||
|
|
||||||
|
void and();
|
||||||
|
void or();
|
||||||
|
void not();
|
||||||
|
|
||||||
|
void pop();
|
||||||
|
void push();
|
||||||
|
|
||||||
|
void inst_ret();
|
||||||
|
void next();
|
||||||
|
void getvalue();
|
||||||
|
void isEnd();
|
||||||
|
void getiter();
|
||||||
|
|
||||||
|
TempVariable popValue()
|
||||||
|
{
|
||||||
|
if (stack.size() == 0)
|
||||||
|
throw std::runtime_error("invaild");
|
||||||
|
auto v = stack.back();
|
||||||
|
stack.pop_back();
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
inline void pushValue(const TempVariable & t) {
|
||||||
|
stack.emplace_back(t);
|
||||||
|
}
|
||||||
|
struct CallStackValue
|
||||||
|
{
|
||||||
|
FunctionCode * frame;
|
||||||
|
pos_t address;
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
std::list<std::unordered_map<std::string, BoxedVar> > variableMap;
|
||||||
|
std::vector<TempVariable> stack;
|
||||||
|
std::vector<CallStackValue> callstack;
|
||||||
|
FunctionCode * instcodes;
|
||||||
|
FunctionCode * programFrame;
|
||||||
|
pos_t programFrameEnd;
|
||||||
|
pos_t programCounter;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
11
LightScript/aaa.ls
Normal file
11
LightScript/aaa.ls
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
var sum = fn(x,y)
|
||||||
|
var r = 0
|
||||||
|
var i = x
|
||||||
|
while y >= i do
|
||||||
|
r = r + i
|
||||||
|
i = i+1
|
||||||
|
end
|
||||||
|
return r
|
||||||
|
end
|
||||||
|
var a = sum(1,10)
|
||||||
|
print(a)
|
202
LightScript/main.cpp
Normal file
202
LightScript/main.cpp
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <list>
|
||||||
|
#include "Lexer.h"
|
||||||
|
#include "Parser.h"
|
||||||
|
#include "VirtualMachine.h"
|
||||||
|
|
||||||
|
class Option {
|
||||||
|
public:
|
||||||
|
Option(int n, const char ** v) :argnum(n), argvalue(v),cur(1)
|
||||||
|
{}
|
||||||
|
|
||||||
|
const char * find(const char * optname) {
|
||||||
|
for (size_t i = cur; i < argnum; i++)
|
||||||
|
{
|
||||||
|
if (strcmp(argvalue[i], optname) == 0)
|
||||||
|
{
|
||||||
|
if (i + 1 < argnum)
|
||||||
|
{
|
||||||
|
return argvalue[i + 1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << "invailed argument";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
const char * getFile() {
|
||||||
|
return argvalue[cur++];
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
int argnum;
|
||||||
|
const char ** argvalue;
|
||||||
|
|
||||||
|
int cur;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void usage()
|
||||||
|
{
|
||||||
|
std::cout <<
|
||||||
|
"usage : LightScript inputfile [-m][-d]\n"
|
||||||
|
" -m, --mode : intepreter, lua_script\n"
|
||||||
|
" (default is native)\n"
|
||||||
|
" -d --debug : true, false\n"
|
||||||
|
" (default is false)\n"
|
||||||
|
" -o --output : path of the output file\n"
|
||||||
|
" only needed if mode is lua_script.\n"
|
||||||
|
" (default is \"./output.lua\")\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
//std::shared_ptr<CompoundType> call(std::vector<BoxedVar> & stack)
|
||||||
|
std::shared_ptr<ls::CompoundType> my_print(std::vector<ls::BoxedVar> & stack) {
|
||||||
|
std::cout << stack[0].to_string() << std::endl;
|
||||||
|
return ls::createVar();
|
||||||
|
}
|
||||||
|
|
||||||
|
//=================================
|
||||||
|
//option
|
||||||
|
//=================================
|
||||||
|
bool debug = false;
|
||||||
|
std::string mode = "native";
|
||||||
|
std::string output_path = "./output.lua";
|
||||||
|
//=================================
|
||||||
|
void setOption(Option & opt);
|
||||||
|
|
||||||
|
int main(int argc, const char * argv[]) {
|
||||||
|
Option opt(argc, argv);
|
||||||
|
if (argc == 1) {
|
||||||
|
usage();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
std::string filename(opt.getFile());
|
||||||
|
|
||||||
|
setOption(opt);
|
||||||
|
|
||||||
|
std::list<ls::Token> tokens;
|
||||||
|
ls::GenerationContext gct;
|
||||||
|
ls::VirtualMachine vm;
|
||||||
|
{
|
||||||
|
std::ifstream file(filename);
|
||||||
|
|
||||||
|
ls::IstreamTokenizer tokenizer(file);
|
||||||
|
ls::Token t;
|
||||||
|
do {
|
||||||
|
t = tokenizer.get();
|
||||||
|
tokens.push_back(t);
|
||||||
|
} while (t.type != ls::ttEof);
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
std::cout <<
|
||||||
|
"========================\n"
|
||||||
|
"tokens\n"
|
||||||
|
"========================\n";
|
||||||
|
for (auto it : tokens)
|
||||||
|
{
|
||||||
|
std::cout << it;
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
ls::Parser ps;
|
||||||
|
ps.set(tokens.begin());
|
||||||
|
std::unique_ptr<ls::AST_SentenceList> tree;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
tree = ps.parseSentenceList();
|
||||||
|
}
|
||||||
|
catch (const ls::ExpectedException & e)
|
||||||
|
{
|
||||||
|
std::cout <<"Grammar error : "<< e.what() << "\n"
|
||||||
|
" line : " << e.line << "\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
std::cout << "========================\n"
|
||||||
|
<<"tree\n"
|
||||||
|
<<"========================\n"
|
||||||
|
<<tree << std::endl;
|
||||||
|
}
|
||||||
|
if (mode == "native") {
|
||||||
|
tree->generateCode(gct);
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
std::cout <<"========================\n"
|
||||||
|
"instruction code\n"
|
||||||
|
"========================\n"
|
||||||
|
<< gct
|
||||||
|
<< "========================\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(mode == "lua_script") {
|
||||||
|
std::ofstream output(output_path);
|
||||||
|
if (!output.is_open()) {
|
||||||
|
std::cout << "open failed!\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
ls::LuaScriptGenerateContext lsgc;
|
||||||
|
lsgc.out(output);
|
||||||
|
tree->luaCodeGen(lsgc);
|
||||||
|
output.close();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
std::cout << "invailed mode input";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
vm.setVar("print") = ls::createBoxedFunction(my_print);
|
||||||
|
vm.set(gct.getFrame());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (vm.runOneCode());
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
std::cout << e.what();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setOption(Option & opt) {
|
||||||
|
const char * d1 = opt.find("-d");
|
||||||
|
if (d1 != nullptr)
|
||||||
|
{
|
||||||
|
debug |= (strcmp(d1, "true") == 0);
|
||||||
|
}
|
||||||
|
const char * d2 = opt.find("--debug");
|
||||||
|
if (d2 != nullptr)
|
||||||
|
{
|
||||||
|
debug |= (strcmp(d2, "true") == 0);
|
||||||
|
}
|
||||||
|
const char * t1 = opt.find("-m");
|
||||||
|
const char * t2 = opt.find("--mode");
|
||||||
|
if (t1 != nullptr)
|
||||||
|
{
|
||||||
|
mode = t1;
|
||||||
|
}
|
||||||
|
if (t2 != nullptr)
|
||||||
|
{
|
||||||
|
mode = t2;
|
||||||
|
}
|
||||||
|
t1 = opt.find("-o");
|
||||||
|
t2 = opt.find("--ouput");
|
||||||
|
if (t1 != nullptr)
|
||||||
|
{
|
||||||
|
output_path = t1;
|
||||||
|
}
|
||||||
|
if (t2 != nullptr)
|
||||||
|
{
|
||||||
|
output_path = t2;
|
||||||
|
}
|
||||||
|
}
|
12
LightScript/output.lua
Normal file
12
LightScript/output.lua
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
sum = function(x,y)
|
||||||
|
local r = 0
|
||||||
|
local i = x
|
||||||
|
while y>=i do
|
||||||
|
r = r+i
|
||||||
|
i = i+1
|
||||||
|
end
|
||||||
|
return r
|
||||||
|
end
|
||||||
|
|
||||||
|
a = sum(1,10)
|
||||||
|
print(a)
|
44
replacePragmaOnce.py
Normal file
44
replacePragmaOnce.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import os
|
||||||
|
import glob
|
||||||
|
|
||||||
|
def checkContent(lst,oper):
|
||||||
|
if len(lst) < len(oper):
|
||||||
|
return False
|
||||||
|
for i,k in enumerate(oper):
|
||||||
|
if lst[i].strip() != k:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def replacePragmaOnce(name):
|
||||||
|
hitContents=False
|
||||||
|
with open(name,"r") as file:
|
||||||
|
temp = open(name+".temp","w")
|
||||||
|
nameheader = os.path.splitext(os.path.split(name)[-1])[0]
|
||||||
|
for line in file:
|
||||||
|
words = line.split()
|
||||||
|
if hitContents:
|
||||||
|
pass
|
||||||
|
elif checkContent(words,["#pragma","once"]):
|
||||||
|
continue
|
||||||
|
elif line.startswith("#ifndef"):
|
||||||
|
temp.close()
|
||||||
|
os.remove(name+".temp")
|
||||||
|
return None
|
||||||
|
elif line.startswith("#include"):
|
||||||
|
pass
|
||||||
|
elif len(words)==0:
|
||||||
|
pass
|
||||||
|
elif line.strip() == "":
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
temp.write("#ifndef LS_{}_H_\n".format(nameheader))
|
||||||
|
temp.write("#define LS_{}_H_\n".format(nameheader))
|
||||||
|
hitContents=True
|
||||||
|
temp.writelines(line)
|
||||||
|
temp.write("\n#endif")
|
||||||
|
temp.close()
|
||||||
|
os.remove(name)
|
||||||
|
os.rename(name+".temp",name)
|
||||||
|
|
||||||
|
for pth in glob.iglob('LightScript\\*.h'):
|
||||||
|
replacePragmaOnce(pth)
|
5
가상머신 필독.txt
Normal file
5
가상머신 필독.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
ByteCode.h 에 있는 code_t 에 일단 명령어 있음.
|
||||||
|
|
||||||
|
가상머신 스택 항상 첫번째로 꺼낸 것이 왼쪽. 두번째가 오른쪽.
|
||||||
|
|
||||||
|
64비트 전용임.
|
Loading…
Reference in New Issue
Block a user