From 837bc19293be009e55259ed38f4cfb0119ee5bff Mon Sep 17 00:00:00 2001 From: monoid Date: Fri, 13 Jan 2023 00:13:17 +0900 Subject: [PATCH] initial commit --- LightScript.sln | 31 ++ LightScript/AST.cpp | 210 +++++++++++ LightScript/AST.h | 439 +++++++++++++++++++++++ LightScript/BoxedVar.cpp | 10 + LightScript/BoxedVar.h | 44 +++ LightScript/ByteCode.cpp | 44 +++ LightScript/ByteCode.h | 110 ++++++ LightScript/CodeGeneration.cpp | 37 ++ LightScript/CodeGeneration.h | 63 ++++ LightScript/CompoundType.cpp | 134 +++++++ LightScript/CompoundType.h | 312 +++++++++++++++++ LightScript/Lexer.cpp | 111 ++++++ LightScript/Lexer.h | 25 ++ LightScript/LightScript.vcxproj | 145 ++++++++ LightScript/LightScript.vcxproj.filters | 92 +++++ LightScript/LightScript.vcxproj.user | 11 + LightScript/LuaScriptGeneration.h | 23 ++ LightScript/Operators.cpp | 14 + LightScript/Operators.h | 30 ++ LightScript/Parser.cpp | 447 ++++++++++++++++++++++++ LightScript/Parser.h | 75 ++++ LightScript/Token.cpp | 20 ++ LightScript/Token.h | 37 ++ LightScript/VirtualMachine.cpp | 435 +++++++++++++++++++++++ LightScript/VirtualMachine.h | 126 +++++++ LightScript/aaa.ls | 11 + LightScript/main.cpp | 202 +++++++++++ LightScript/output.lua | 12 + README.md | 2 + replacePragmaOnce.py | 44 +++ 가상머신 필독.txt | 5 + 31 files changed, 3301 insertions(+) create mode 100644 LightScript.sln create mode 100644 LightScript/AST.cpp create mode 100644 LightScript/AST.h create mode 100644 LightScript/BoxedVar.cpp create mode 100644 LightScript/BoxedVar.h create mode 100644 LightScript/ByteCode.cpp create mode 100644 LightScript/ByteCode.h create mode 100644 LightScript/CodeGeneration.cpp create mode 100644 LightScript/CodeGeneration.h create mode 100644 LightScript/CompoundType.cpp create mode 100644 LightScript/CompoundType.h create mode 100644 LightScript/Lexer.cpp create mode 100644 LightScript/Lexer.h create mode 100644 LightScript/LightScript.vcxproj create mode 100644 LightScript/LightScript.vcxproj.filters create mode 100644 LightScript/LightScript.vcxproj.user create mode 100644 LightScript/LuaScriptGeneration.h create mode 100644 LightScript/Operators.cpp create mode 100644 LightScript/Operators.h create mode 100644 LightScript/Parser.cpp create mode 100644 LightScript/Parser.h create mode 100644 LightScript/Token.cpp create mode 100644 LightScript/Token.h create mode 100644 LightScript/VirtualMachine.cpp create mode 100644 LightScript/VirtualMachine.h create mode 100644 LightScript/aaa.ls create mode 100644 LightScript/main.cpp create mode 100644 LightScript/output.lua create mode 100644 README.md create mode 100644 replacePragmaOnce.py create mode 100644 가상머신 필독.txt diff --git a/LightScript.sln b/LightScript.sln new file mode 100644 index 0000000..5a0aebc --- /dev/null +++ b/LightScript.sln @@ -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 diff --git a/LightScript/AST.cpp b/LightScript/AST.cpp new file mode 100644 index 0000000..bf38e40 --- /dev/null +++ b/LightScript/AST.cpp @@ -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(op)); + return ret + 1; +} + +int ls::AST_Unary::generateCode(GenerationContext & t) +{ + int ret = LHS->generateCode(t); + t.push(static_cast(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(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; +} diff --git a/LightScript/AST.h b/LightScript/AST.h new file mode 100644 index 0000000..f387fa1 --- /dev/null +++ b/LightScript/AST.h @@ -0,0 +1,439 @@ +#include +#include +#include +#include +#include + +#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 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 > 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 & rhs) { + rhs->printDebugInfo(os); + return os; + } + inline std::ostream & operator<<(std::ostream & os, std::unique_ptr & rhs) { + rhs->printDebugInfo(os); + return os; + } + inline std::ostream & operator<<(std::ostream & os, std::unique_ptr & rhs) { + rhs->printDebugInfo(os); + return os; + } + inline std::ostream & operator<<(std::ostream & os, std::unique_ptr & rhs) { + rhs->printDebugInfo(os); + return os; + } + inline std::ostream & operator<<(std::ostream & os, std::unique_ptr & rhs) { + rhs->printDebugInfo(os); + return os; + } + + class AST_CommonSentence : public AST_Sentence { + public: + explicit AST_CommonSentence(std::unique_ptr 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 expression; + }; + class AST_VarSentence : public AST_Sentence { + public: + AST_VarSentence(std::unique_ptr lhs, std::unique_ptr 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 LHS; + std::unique_ptr RHS; + }; + class AST_AssignmentSentence : public AST_Sentence { + public: + AST_AssignmentSentence(std::unique_ptr lhs, std::unique_ptr 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 LHS; + std::unique_ptr RHS; + }; + class AST_If : public AST_Sentence { + public: + explicit AST_If(std::unique_ptr cond, std::unique_ptr s) + :condition(move(cond)), ifSentence(move(s)),elseSentence(nullptr) {} + virtual int generateCode(GenerationContext &); + void setElse(std::unique_ptr 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 condition; + std::unique_ptr ifSentence; + std::unique_ptr elseSentence; + }; + class AST_While : public AST_Sentence { + public: + explicit AST_While(std::unique_ptr cond, std::unique_ptr 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 condition; + std::unique_ptr sentences; + }; + class AST_ForIn : public AST_Sentence { + public: + explicit AST_ForIn(std::unique_ptr i,std::unique_ptr cond, + std::unique_ptr 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 id; + std::unique_ptr iterable; + std::unique_ptr 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 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 return_value; + }; + class AST_Binary : public AST_Expr { + public: + explicit AST_Binary(Opers oper, std::unique_ptr l, std::unique_ptr 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 LHS, RHS; + }; + class AST_Unary : public AST_Expr { + public: + explicit AST_Unary(Opers oper, std::unique_ptr 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 LHS; + }; + class AST_Index : public AST_Variable { + public: + explicit AST_Index(std::unique_ptr l, std::unique_ptr 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 LHS, RHS; + }; + class AST_Dot : public AST_Variable { + public: + explicit AST_Dot(std::unique_ptr l, std::unique_ptr 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 LHS; + std::unique_ptr RHS; + }; + class AST_CallExpr : public AST_Variable { + public: + explicit AST_CallExpr(std::unique_ptr l) + :callee(move(l)){} + void push_back(std::unique_ptr 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 callee; + std::list> args; + }; + class AST_Function : public AST_Expr { + public: + void push_back(std::unique_ptr arg) { args.emplace_back(move(arg)); } + void setSentenceList(std::unique_ptr 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> args; + std::unique_ptr sentences; + }; + + template + 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 { + public: + using AST_Value::AST_Value; + }; + class AST_Float : public AST_Value { + public: + using AST_Value::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 \ No newline at end of file diff --git a/LightScript/BoxedVar.cpp b/LightScript/BoxedVar.cpp new file mode 100644 index 0000000..c6e3aaf --- /dev/null +++ b/LightScript/BoxedVar.cpp @@ -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; +} diff --git a/LightScript/BoxedVar.h b/LightScript/BoxedVar.h new file mode 100644 index 0000000..a8f348a --- /dev/null +++ b/LightScript/BoxedVar.h @@ -0,0 +1,44 @@ +#include +#include +#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 t) : + ptr(createVar(name,move(t))) {} + explicit BoxedVar(std::function(std::vector&)> t, function_tag) : + ptr(createVar(t)) {} + BoxedVar(const BoxedVar & var); + explicit BoxedVar(const std::shared_ptr & t) + :ptr(t){} + explicit BoxedVar(const std::shared_ptr && t) + :ptr(std::move(t)) {} + + std::shared_ptr get() const { return ptr; } + void set(const std::shared_ptr & t) { ptr = t; } + + std::string to_string() const { return ptr->to_string(); } + private: + std::shared_ptr ptr; + }; + inline BoxedVar createBoxedFunction(std::function(std::vector&)> t) { + return BoxedVar(t, function_tag()); + } +} +#endif \ No newline at end of file diff --git a/LightScript/ByteCode.cpp b/LightScript/ByteCode.cpp new file mode 100644 index 0000000..a359ba7 --- /dev/null +++ b/LightScript/ByteCode.cpp @@ -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(t)]; + return "Error"; +} diff --git a/LightScript/ByteCode.h b/LightScript/ByteCode.h new file mode 100644 index 0000000..cf6e8bf --- /dev/null +++ b/LightScript/ByteCode.h @@ -0,0 +1,110 @@ + +#include +#include +#include +#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 code; + std::vector operands; + }; + struct InstructionCode { + FunctionCode mainframe; + FunctionCode * ptr; + explicit InstructionCode() { + ptr = &mainframe; + } + + FunctionCode * operator->() { return ptr; } + const FunctionCode * operator->() const { return ptr; } + }; +} + +#endif \ No newline at end of file diff --git a/LightScript/CodeGeneration.cpp b/LightScript/CodeGeneration.cpp new file mode 100644 index 0000000..6f64301 --- /dev/null +++ b/LightScript/CodeGeneration.cpp @@ -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(); +} diff --git a/LightScript/CodeGeneration.h b/LightScript/CodeGeneration.h new file mode 100644 index 0000000..0079817 --- /dev/null +++ b/LightScript/CodeGeneration.h @@ -0,0 +1,63 @@ +#include +#include +#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(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 continue_pos; + std::vector break_pos; + }; + std::vector lpos; + }; + std::ostream & operator<<(std::ostream & os, const GenerationContext & a); +} + +#endif \ No newline at end of file diff --git a/LightScript/CompoundType.cpp b/LightScript/CompoundType.cpp new file mode 100644 index 0000000..02868b6 --- /dev/null +++ b/LightScript/CompoundType.cpp @@ -0,0 +1,134 @@ +#include +#include "CompoundType.h" +#include"ByteCode.h" + +using namespace ls; + +shared_ptr 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 ls::BooleanType::unaryGo(Opers op) +{ + if (op == kNot) { + return createVar(!value); + } + return nullptr; +} + +shared_ptr ls::BooleanType::binaryGo(Opers op, CompoundType * rhs) +{ + auto r = dynamic_cast(rhs); + if (r == nullptr) return nullptr; + auto ret = LogicalBinaryGo(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 ls::BooleanType::copy() +{ + return createVar(value); +} + +shared_ptr ls::IntegerType::unaryGo(Opers op) +{ + return ArithmeticUnaryGo(op, value); +} + +shared_ptr ls::IntegerType::binaryGo(Opers op, CompoundType * rhs) +{ + switch (rhs->Type()) { + case kInteger: + return ArithmeticBinaryGo(op, value, dynamic_cast(rhs)->value); + break; + case kFloat: + return ArithmeticBinaryGo(op, value, dynamic_cast(rhs)->value); + break; + case kString: + if (op== kAdd){ + return createVar(to_string() + dynamic_cast(rhs)->value); + } + break; + } + return nullptr; +} + +shared_ptr ls::IntegerType::copy() +{ + return createVar(value); +} + +shared_ptr ls::FloatType::unaryGo(Opers op) +{ + return ArithmeticUnaryGo(op, value); +} + +shared_ptr ls::FloatType::binaryGo(Opers op, CompoundType * rhs) +{ + switch (rhs->Type()) { + case kInteger: + return ArithmeticBinaryGo(op, value, dynamic_cast(rhs)->value); + break; + case kFloat: + return ArithmeticBinaryGo(op, value, dynamic_cast(rhs)->value); + break; + default: + return nullptr; + break; + } +} + +shared_ptr ls::FloatType::copy() +{ + return createVar(value); +} + +shared_ptr ls::StringType::binaryGo(Opers op, CompoundType * rhs) +{ + if (op != kAdd) + return nullptr; + return createVar(value + rhs->to_string()); +} + +shared_ptr 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; +} diff --git a/LightScript/CompoundType.h b/LightScript/CompoundType.h new file mode 100644 index 0000000..01ab3d3 --- /dev/null +++ b/LightScript/CompoundType.h @@ -0,0 +1,312 @@ +#include +#include +#include +#include +#include +#include +#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 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 unaryGo(Opers op) { return nullptr; } + virtual shared_ptr binaryGo(Opers op, CompoundType *); + + virtual TypeKind Type() = 0; + + virtual shared_ptr copy() { return nullptr; } + + //virtual std::shared_ptr cast(TypeKind tk) { throw InvalidOperation(); } + virtual std::string to_string() { return ""; } + virtual ~CompoundType() {} + + virtual size_t hash() { return reinterpret_cast(this); } + }; +} +namespace std { + template<> struct hash + { + 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 unaryGo(Opers op) override; + virtual shared_ptr binaryGo(Opers op, CompoundType * rhs) override; + virtual size_t hash() override { return std::hash{}(value); }; + virtual shared_ptr 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 unaryGo(Opers op) override; + virtual shared_ptr binaryGo(Opers op, CompoundType * rhs) override; + virtual size_t hash() override { return value; }; + virtual shared_ptr 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 unaryGo(Opers op) override; + virtual shared_ptr binaryGo(Opers op, CompoundType * rhs) override; + virtual size_t hash() override { return std::hash{}(value); }; + virtual shared_ptr 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 unaryGo(Opers op) override { return nullptr; } + virtual shared_ptr binaryGo(Opers op, CompoundType * rhs) override; + virtual size_t hash() override { return std::hash{}(value); }; + virtual shared_ptr copy(); + + std::string value; + }; + + typedef std::unordered_map< CompoundType *, shared_ptr > 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 ""; + } + inline virtual bool next() override { + if (cur != end) + cur++; + return true; + } + inline bool isEnd() { + return cur != end; + } + inline shared_ptr & 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 getiter() { + return make_shared(map.begin(), map.end()); + } + private: + dict_type map; + }; + class FunctionProxyType : public CompoundType { + public: + explicit FunctionProxyType(std::function(std::vector&)> v) :value(v) {} + std::shared_ptr call(std::vector & stack) { + return value(stack); + } + virtual TypeKind Type() override { return TypeKind::kFunctionProxy; } + virtual std::string to_string() override { return debugName; } + std::string debugName = ""; + std::function(std::vector&)> value; + }; + + struct FunctionCodeDeleter{ + void operator()(FunctionCode * ); + }; + + class FunctionType : public CompoundType { + public: + FunctionType(const std::string & n, std::unique_ptr c) + :name(n), code(move(c)) {} + + virtual TypeKind Type() override { return TypeKind::kFunction; } + virtual std::string to_string() override { return ""; } + public: + std::string name = ""; + std::unique_ptr code; + }; + inline std::shared_ptr createVar(void) { + static std::shared_ptr < CompoundType > ret(new NoneType); + return ret; + } + inline std::shared_ptr createVar(int64_t t) { + return std::make_shared(t); + } + inline std::shared_ptr createVar(int t) { + return std::make_shared(t); + } + inline std::shared_ptr createVar(bool t) { + return std::make_shared(t); + } + inline std::shared_ptr createVar(double t) { + return std::make_shared(t); + } + inline std::shared_ptr createVar(const std::string & t) { + return std::make_shared(t); + } + inline std::shared_ptr createVar(std::function(std::vector&)> v) { + return std::make_shared(v); + } + inline std::shared_ptr createVar(const std::string & name, std::unique_ptr t) { + return std::make_shared(name, move(t)); + } + template + shared_ptr 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 + shared_ptr 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 + shared_ptr 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 \ No newline at end of file diff --git a/LightScript/Lexer.cpp b/LightScript/Lexer.cpp new file mode 100644 index 0000000..c96976e --- /dev/null +++ b/LightScript/Lexer.cpp @@ -0,0 +1,111 @@ +#include +#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; +} diff --git a/LightScript/Lexer.h b/LightScript/Lexer.h new file mode 100644 index 0000000..d919441 --- /dev/null +++ b/LightScript/Lexer.h @@ -0,0 +1,25 @@ +#include +#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 \ No newline at end of file diff --git a/LightScript/LightScript.vcxproj b/LightScript/LightScript.vcxproj new file mode 100644 index 0000000..ab24335 --- /dev/null +++ b/LightScript/LightScript.vcxproj @@ -0,0 +1,145 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {99DA223F-E88F-4E97-A314-E798486955A8} + LightScript + 10.0.16299.0 + + + + Application + true + v141 + MultiByte + + + Application + false + v141 + true + MultiByte + + + Application + true + v141 + MultiByte + + + Application + false + v141 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + + + Level3 + Disabled + true + + + + + Level3 + Disabled + true + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/LightScript/LightScript.vcxproj.filters b/LightScript/LightScript.vcxproj.filters new file mode 100644 index 0000000..6132898 --- /dev/null +++ b/LightScript/LightScript.vcxproj.filters @@ -0,0 +1,92 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + + + 리소스 파일 + + + \ No newline at end of file diff --git a/LightScript/LightScript.vcxproj.user b/LightScript/LightScript.vcxproj.user new file mode 100644 index 0000000..69514b2 --- /dev/null +++ b/LightScript/LightScript.vcxproj.user @@ -0,0 +1,11 @@ + + + + aaa.ls --debug true --mode lua_script + WindowsLocalDebugger + + + aaa.ls --debug true --mode lua_script + WindowsLocalDebugger + + \ No newline at end of file diff --git a/LightScript/LuaScriptGeneration.h b/LightScript/LuaScriptGeneration.h new file mode 100644 index 0000000..0806543 --- /dev/null +++ b/LightScript/LuaScriptGeneration.h @@ -0,0 +1,23 @@ +#include + +#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 + diff --git a/LightScript/Operators.cpp b/LightScript/Operators.cpp new file mode 100644 index 0000000..bb207f2 --- /dev/null +++ b/LightScript/Operators.cpp @@ -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]; +} diff --git a/LightScript/Operators.h b/LightScript/Operators.h new file mode 100644 index 0000000..57a098a --- /dev/null +++ b/LightScript/Operators.h @@ -0,0 +1,30 @@ +#include + +#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 \ No newline at end of file diff --git a/LightScript/Parser.cpp b/LightScript/Parser.cpp new file mode 100644 index 0000000..b734bfe --- /dev/null +++ b/LightScript/Parser.cpp @@ -0,0 +1,447 @@ +#include "Parser.h" + +using namespace ls; + +using std::make_unique; + +unique_ptr ls::Parser::parseSentenceList() +{ + auto ret = make_unique(); + for (;;) { + auto sentence = parseSentence(); + if (sentence == nullptr) + break; + ret->push_back(move(sentence)); + } + return ret; +} + +unique_ptr ls::Parser::parseSentence() +{ + unique_ptr ret; + if (it->str == "continue") { + it++; + ret = make_unique(); + } + else if (it->str == "break") { + it++; + ret = make_unique(); + } + 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 ls::Parser::parseCommonSentence() +{ + unique_ptr ret; + auto lvalue = expr(); + if (lvalue == nullptr) return nullptr; + if (it->str == "=") { + it++; + auto r = expr(); + return make_unique(move(lvalue), move(r)); + } + return make_unique(move(lvalue)); +} + +unique_ptr 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(move(lv), move(r))); + } + return nullptr; +} + +unique_ptr 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(move(lv), move(r))); + } + return nullptr; +} + +unique_ptr 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(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 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(move(id), move(lv), move(sl)); + } + return nullptr; +} + +unique_ptr ls::Parser::parseReturn() +{ + if (it->str == "return") { + it++; + auto retValue = expr(); + if (retValue != nullptr) + return make_unique(move(retValue)); + else + return make_unique(make_unique()); + } + return nullptr; +} + +unique_ptr Parser::parseLogicalBinary() +{ + unique_ptr 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(kAnd,move(LHS), move(RHS)); + else if (op == "or") + LHS = make_unique(kOr,move(LHS), move(RHS)); + } + return LHS; +} + +unique_ptr ls::Parser::parseLogicalUnary() +{ + if (it->str == "not") { + ++it; + auto ret = parseComparison(); + if (ret == nullptr) + ThrowExpected("Expected Expression"); + return make_unique(kNot,move(ret)); + } + return parseComparison(); +} + +unique_ptr ls::Parser::parseComparison() +{ + unique_ptr 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(kEqual, move(LHS), move(RHS)); + else if (op == "!=") + LHS = make_unique(kNotEqual, move(LHS), move(RHS)); + else if (op == ">") + LHS = make_unique(kGreater, move(LHS), move(RHS)); + else if (op == ">=") + LHS = make_unique(kEqualGreater, move(LHS), move(RHS)); + else if (op == "<") + LHS = make_unique(kLess, move(LHS), move(RHS)); + else if (op == "<=") + LHS = make_unique(kLessEqual, move(LHS), move(RHS)); + } + return LHS; +} + +unique_ptr ls::Parser::parseAddAndSub() //code 丵 . +{ + unique_ptr LHS, RHS; + if (it->str == "+") { + ++it; + LHS = parseMulAndDiv(); + if (LHS == nullptr) + ThrowExpected("Expected Expression"); + LHS = make_unique(kPlus,move(LHS)); + } + else if (it->str == "-") { + ++it; + LHS = parseMulAndDiv(); + if (LHS == nullptr) + ThrowExpected("Expected Expression"); + LHS = make_unique(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(kAdd,move(LHS), move(RHS)); + else if (op == "-") + LHS = make_unique(kSub,move(LHS), move(RHS)); + } + return LHS; +} + +unique_ptr ls::Parser::parseMulAndDiv() +{ + unique_ptr 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(kMul,move(LHS), move(RHS)); + else if (op == "/") + LHS = make_unique(kDiv,move(LHS), move(RHS)); + } + return LHS; +} + +unique_ptr ls::Parser::parseAttrAccess() +{ + unique_ptr 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(move(LHS), move(RHS)); + } + else if (it->str == ".") { + it++; + auto RHS = parseIdentifier(); + LHS = make_unique(move(LHS), move(RHS)); + } + else if (it->str == "(") { + ++it; + auto L = make_unique(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 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 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 Parser::parseInteger() +{ + if (it->type != TokenType::ttInteger) + return nullptr; + auto value = std::stoll(it->str); + it++; + return make_unique(value); +} + +unique_ptr Parser::parseFloating() +{ + if (it->type != TokenType::ttFloat) + return nullptr; + auto value = std::stod(it->str); + it++; + return make_unique(value); +} + +unique_ptr ls::Parser::parseFunction() +{ + if (it->str != "fn") + return nullptr; + it++; + if (it->str != "(") + ThrowExpected("expected \'(\'"); + auto L = make_unique(); + 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 ls::Parser::parseTableExpr() +{ + return nullptr; +} + +unique_ptr ls::Parser::parseIdentifier() +{ + if (it->type == ttIdentifier) { + auto ret = make_unique(it->str); + it++; + return ret; + } + return nullptr; +} diff --git a/LightScript/Parser.h b/LightScript/Parser.h new file mode 100644 index 0000000..69dbc41 --- /dev/null +++ b/LightScript/Parser.h @@ -0,0 +1,75 @@ + +#include + +#include +#include +#include"Token.h" +#include"AST.h" + + +#ifndef LS_Parser_H_ +#define LS_Parser_H_ +namespace ls { + typedef std::list 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 parseSentenceList(); + unique_ptr parseSentence(); + inline unique_ptr expr() { return parseLogicalBinary(); } + private: + unique_ptr parseCommonSentence(); + unique_ptr parseVarSentence(); + unique_ptr parseWhileSentence(); + unique_ptr parseIfSentence(); + unique_ptr parseForInSentence(); + unique_ptr parseReturn(); + private: + // := {("and"|"or")-} + unique_ptr parseLogicalBinary(); + // := ["not"] + unique_ptr parseLogicalUnary(); + // := {("=="|"!="|"<="|"<"|">="|">")-} + unique_ptr parseComparison(); + // := ["+"|"-"]{("+"|"-")-} + unique_ptr parseAddAndSub(); + // := {("*"|"/")-} + unique_ptr parseMulAndDiv(); + // := {("["--"]")|("("-([],{","-})-")")|"."} + unique_ptr parseAttrAccess(); + // := "("--")"|| + unique_ptr parsePrimary(); + // := |||| + unique_ptr parseLiteral(); + unique_ptr parseInteger(); + unique_ptr parseFloating(); + unique_ptr parseFunction(); + //ϼ ȵ. + unique_ptr parseTableExpr(); + + unique_ptr parseIdentifier(); + + //unique_ptr level6() + private: + Tokit it; + Tokit end; + }; +} +#endif \ No newline at end of file diff --git a/LightScript/Token.cpp b/LightScript/Token.cpp new file mode 100644 index 0000000..d8732be --- /dev/null +++ b/LightScript/Token.cpp @@ -0,0 +1,20 @@ +#include +#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; +} diff --git a/LightScript/Token.h b/LightScript/Token.h new file mode 100644 index 0000000..b05e057 --- /dev/null +++ b/LightScript/Token.h @@ -0,0 +1,37 @@ +#include +#include +#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 \ No newline at end of file diff --git a/LightScript/VirtualMachine.cpp b/LightScript/VirtualMachine.cpp new file mode 100644 index 0000000..268228c --- /dev/null +++ b/LightScript/VirtualMachine.cpp @@ -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(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(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(kInteger); + programCounter += s->value; + programCounter--; +} + +void ls::VirtualMachine::jt() +{ + auto jmp_count = popValue(); + auto condition = popValue(); + auto jmp = jmp_count.cast(kInteger); + auto cond = condition.cast(kBoolean); + if (cond->value) { + programCounter += jmp->value; + programCounter--; + } +} + +void ls::VirtualMachine::jf() +{ + auto jmp_count = popValue(); + auto condition = popValue(); + auto jmp = jmp_count.cast(kInteger); + auto cond = condition.cast(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(kTableIter); + TempVariable tmp; + tmp.val()->set(t->value()); + pushValue(LHS); + pushValue(tmp); +} + +void ls::VirtualMachine::isEnd() +{ + auto LHS = popValue(); + auto t = LHS.cast(kTableIter); + TempVariable tmp; + tmp.val()->set(createVar(t->isEnd())); + pushValue(LHS); + pushValue(tmp); +} + +void ls::VirtualMachine::getiter() +{ + auto LHS = popValue(); + auto table = LHS.cast(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(f.get()); + auto arg_numT = popValue(); + auto arg_num = arg_numT.cast(kInteger); + std::vector 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(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); +} diff --git a/LightScript/VirtualMachine.h b/LightScript/VirtualMachine.h new file mode 100644 index 0000000..08a880e --- /dev/null +++ b/LightScript/VirtualMachine.h @@ -0,0 +1,126 @@ +#include +#include +#include +#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 + Ty * cast(TypeKind t) { + auto ret = get(); + if (ret->Type() != t) + throw std::exception("Invaild Type Casting Error!"); + return static_cast(ret); + } + }; + class VirtualMachine { + public: + VirtualMachine(){ + std::unordered_map 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 > variableMap; + std::vector stack; + std::vector callstack; + FunctionCode * instcodes; + FunctionCode * programFrame; + pos_t programFrameEnd; + pos_t programCounter; + }; +} +#endif \ No newline at end of file diff --git a/LightScript/aaa.ls b/LightScript/aaa.ls new file mode 100644 index 0000000..4b1e44a --- /dev/null +++ b/LightScript/aaa.ls @@ -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) \ No newline at end of file diff --git a/LightScript/main.cpp b/LightScript/main.cpp new file mode 100644 index 0000000..b65dc1c --- /dev/null +++ b/LightScript/main.cpp @@ -0,0 +1,202 @@ +#include +#include +#include +#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 call(std::vector & stack) +std::shared_ptr my_print(std::vector & 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 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 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" + <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; + } +} \ No newline at end of file diff --git a/LightScript/output.lua b/LightScript/output.lua new file mode 100644 index 0000000..0eee319 --- /dev/null +++ b/LightScript/output.lua @@ -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) diff --git a/README.md b/README.md new file mode 100644 index 0000000..7461758 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# LightScript + diff --git a/replacePragmaOnce.py b/replacePragmaOnce.py new file mode 100644 index 0000000..48ff41a --- /dev/null +++ b/replacePragmaOnce.py @@ -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) diff --git a/가상머신 필독.txt b/가상머신 필독.txt new file mode 100644 index 0000000..243ef89 --- /dev/null +++ b/가상머신 필독.txt @@ -0,0 +1,5 @@ +ByteCode.h ִ code_t ϴ ɾ . + +ӽ ׻ ù° . ι° . + +64Ʈ . \ No newline at end of file