initial commit

This commit is contained in:
monoid 2023-01-13 00:13:17 +09:00
commit 837bc19293
31 changed files with 3301 additions and 0 deletions

31
LightScript.sln Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View 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();
}

View 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

View 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
View 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
View 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
View 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

View 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>

View 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>

View 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>

View 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
View 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
View 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
View 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
View 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
View 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
View 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

View 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);
}

View 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
View 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
View 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
View 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)

2
README.md Normal file
View File

@ -0,0 +1,2 @@
# LightScript

44
replacePragmaOnce.py Normal file
View 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
View File

@ -0,0 +1,5 @@
ByteCode.h 에 있는 code_t 에 일단 명령어 있음.
가상머신 스택 항상 첫번째로 꺼낸 것이 왼쪽. 두번째가 오른쪽.
64비트 전용임.