diff --git a/.vs/DialogueManagementScript/v16/.suo b/.vs/DialogueManagementScript/v16/.suo new file mode 100644 index 0000000..fd094b2 Binary files /dev/null and b/.vs/DialogueManagementScript/v16/.suo differ diff --git a/.vs/DialogueManagementScript/v16/Browse.VC.db b/.vs/DialogueManagementScript/v16/Browse.VC.db new file mode 100644 index 0000000..35cc9e5 Binary files /dev/null and b/.vs/DialogueManagementScript/v16/Browse.VC.db differ diff --git a/.vs/DialogueManagementScript/v16/ipch/AutoPCH/27d55e5024d948b0/DIALOGUEMANAGEMENTSCRIPT.ipch b/.vs/DialogueManagementScript/v16/ipch/AutoPCH/27d55e5024d948b0/DIALOGUEMANAGEMENTSCRIPT.ipch new file mode 100644 index 0000000..48c8fe3 Binary files /dev/null and b/.vs/DialogueManagementScript/v16/ipch/AutoPCH/27d55e5024d948b0/DIALOGUEMANAGEMENTSCRIPT.ipch differ diff --git a/.vs/DialogueManagementScript/v16/ipch/AutoPCH/726b2dad1d257370/DIALOGUEMANAGEMENTSCRIPT.ipch b/.vs/DialogueManagementScript/v16/ipch/AutoPCH/726b2dad1d257370/DIALOGUEMANAGEMENTSCRIPT.ipch new file mode 100644 index 0000000..dd12ea9 Binary files /dev/null and b/.vs/DialogueManagementScript/v16/ipch/AutoPCH/726b2dad1d257370/DIALOGUEMANAGEMENTSCRIPT.ipch differ diff --git a/.vs/DialogueManagementScript/v16/ipch/AutoPCH/dfc2f93971200137/TOKEN.ipch b/.vs/DialogueManagementScript/v16/ipch/AutoPCH/dfc2f93971200137/TOKEN.ipch new file mode 100644 index 0000000..ae58c0b Binary files /dev/null and b/.vs/DialogueManagementScript/v16/ipch/AutoPCH/dfc2f93971200137/TOKEN.ipch differ diff --git a/DialogueManagementScript.sln b/DialogueManagementScript.sln new file mode 100644 index 0000000..63258ea --- /dev/null +++ b/DialogueManagementScript.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29911.84 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DialogueManagementScript", "DialogueManagementScript\DialogueManagementScript.vcxproj", "{709C242E-2FB4-462A-88F5-009D903C463F}" +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 + {709C242E-2FB4-462A-88F5-009D903C463F}.Debug|x64.ActiveCfg = Debug|x64 + {709C242E-2FB4-462A-88F5-009D903C463F}.Debug|x64.Build.0 = Debug|x64 + {709C242E-2FB4-462A-88F5-009D903C463F}.Debug|x86.ActiveCfg = Debug|Win32 + {709C242E-2FB4-462A-88F5-009D903C463F}.Debug|x86.Build.0 = Debug|Win32 + {709C242E-2FB4-462A-88F5-009D903C463F}.Release|x64.ActiveCfg = Release|x64 + {709C242E-2FB4-462A-88F5-009D903C463F}.Release|x64.Build.0 = Release|x64 + {709C242E-2FB4-462A-88F5-009D903C463F}.Release|x86.ActiveCfg = Release|Win32 + {709C242E-2FB4-462A-88F5-009D903C463F}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {3F3B7427-4F15-495C-8609-9A4FB78D9127} + EndGlobalSection +EndGlobal diff --git a/DialogueManagementScript/DialogueManagementScript.cpp b/DialogueManagementScript/DialogueManagementScript.cpp new file mode 100644 index 0000000..58ea123 --- /dev/null +++ b/DialogueManagementScript/DialogueManagementScript.cpp @@ -0,0 +1,20 @@ +// DialogueManagementScript.cpp : This file contains the 'main' function. Program execution begins and ends there. +// + +#include + +int main() +{ + std::cout << "Hello World!\n"; +} + +// Run program: Ctrl + F5 or Debug > Start Without Debugging menu +// Debug program: F5 or Debug > Start Debugging menu + +// Tips for Getting Started: +// 1. Use the Solution Explorer window to add/manage files +// 2. Use the Team Explorer window to connect to source control +// 3. Use the Output window to see build output and other messages +// 4. Use the Error List window to view errors +// 5. Go to Project > Add New Item to create new code files, or Project > Add Existing Item to add existing code files to the project +// 6. In the future, to open this project again, go to File > Open > Project and select the .sln file diff --git a/DialogueManagementScript/DialogueManagementScript.vcxproj b/DialogueManagementScript/DialogueManagementScript.vcxproj new file mode 100644 index 0000000..fbc0ebc --- /dev/null +++ b/DialogueManagementScript/DialogueManagementScript.vcxproj @@ -0,0 +1,159 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + {709C242E-2FB4-462A-88F5-009D903C463F} + Win32Proj + DialogueManagementScript + 10.0 + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + + + + + \ No newline at end of file diff --git a/DialogueManagementScript/DialogueManagementScript.vcxproj.filters b/DialogueManagementScript/DialogueManagementScript.vcxproj.filters new file mode 100644 index 0000000..5aa9d20 --- /dev/null +++ b/DialogueManagementScript/DialogueManagementScript.vcxproj.filters @@ -0,0 +1,30 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;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 + + + + + Source Files + + + Source Files + + + + + Header Files + + + \ No newline at end of file diff --git a/DialogueManagementScript/DialogueManagementScript.vcxproj.user b/DialogueManagementScript/DialogueManagementScript.vcxproj.user new file mode 100644 index 0000000..88a5509 --- /dev/null +++ b/DialogueManagementScript/DialogueManagementScript.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/DialogueManagementScript/Token.cpp b/DialogueManagementScript/Token.cpp new file mode 100644 index 0000000..cc052ad --- /dev/null +++ b/DialogueManagementScript/Token.cpp @@ -0,0 +1 @@ +#include "Token.h" diff --git a/DialogueManagementScript/Token.h b/DialogueManagementScript/Token.h new file mode 100644 index 0000000..2a01538 --- /dev/null +++ b/DialogueManagementScript/Token.h @@ -0,0 +1,5 @@ +#pragma once +class Token +{ +}; + diff --git a/compiler.lua b/compiler.lua index d471cfa..e682c83 100644 --- a/compiler.lua +++ b/compiler.lua @@ -1,21 +1,30 @@ ---~ t = debug.getmetatable ("") ---~ t.__index = function(self,k) ---~ if type(k)=="number" then ---~ return string.sub(self,k,k) ---~ end ---~ end +function tprint (tbl, indent) + if not indent then indent = 0 end + for k, v in pairs(tbl) do + formatting = string.rep(" ", indent) .. k .. ": " + if type(v) == "table" then + print(formatting) + tprint(v, indent+1) + else + print(formatting .. tostring(v)) + end + end +end + + Token = {} Token.__index = Token -local INTEGER, PLUS, EOF, MINUS, MUL, DIV, LPAREN, RPAREN = "INT","+","EOF", "-", "*", "/", "(", ")" +local INTEGER, PLUS, EOF, MINUS, MUL, DIV, LPAREN, RPAREN, BEGIN, END, DOT, ID, ASSIGN, SEMI = "INT","+","EOF", "-", "*", "/", "(", ")", "BEGIN", "END", "DOT", "ID", "ASSIGN", "SEMI" function Token.__tostring(self) return string.format("Token(%s, %s)",self.type,self.value) end function Token:new(tp,val) local c = {} setmetatable(c,self) + c.Type = 'Token' c.type = tp c.value = val - print("Token:"..tp) + --print("Token:"..tp) return c end @@ -24,22 +33,45 @@ Lexer.__index = Lexer function Lexer:new(text) local c = {} setmetatable(c,self) - self.text = text - self.pos = 1 - self.current_char = self.text:sub(1,1) - self.stop = false + c.Type = 'Lexer' + c.text = text + c.pos = 1 + c.current_char = c.text:sub(1,1) + c.stop = false return c end function Lexer:advance() self.pos = self.pos + 1 if self.pos > #self.text then self.current_char = false + return else self.current_char = self.text:sub(self.pos,self.pos) end end -function Lexer:error() - error("Invalid character") +local RESERVED_KEYWORDS = { + BEGIN = Token:new('BEGIN',BEGIN), + END = Token:new('END',END) +} +function Lexer:_id() + local result = '' + while self.current_char and self.current_char:match("%w") do + result = result .. self.current_char + self:advance() + end + local token = RESERVED_KEYWORDS[result] or Token:new(ID,result) + return token +end +function Lexer:peek() + local peek_pos = self.pos + 1 + if peek_pos > #self.text then + return + else + return self.text:sub(peek_pos,peek_pos) + end +end +function Lexer:error(err) + error(err) end function Lexer:skip_whitespace() while self.current_char and self.current_char:match("%s") do @@ -57,110 +89,392 @@ end function Lexer:get_next_token() while self.current_char do ::continue:: - if self.current_char:match("%s") then + if self.current_char and self.current_char:match("%s") then self:skip_whitespace() goto continue end - if self.current_char:match("%d") then + if self.current_char and self.current_char:match("%d") then return Token:new(INTEGER,self:integer()) end - if self.current_char == "+" then + if self.current_char and self.current_char == "+" then self:advance() return Token:new(PLUS,"+") end - if self.current_char == "-" then--55+77 + if self.current_char and self.current_char == "-" then--55+77 self:advance() return Token:new(MINUS,"-") end - if self.current_char == "*" then + if self.current_char and self.current_char == "*" then self:advance() return Token:new(MUL,"*") end - if self.current_char == "/" then + if self.current_char and self.current_char == "/" then self:advance() return Token:new(DIV,"/") end - if self.current_char == "(" then + if self.current_char and self.current_char == "(" then self:advance() return Token:new(LPAREN,"(") end - if self.current_char == ")" then + if self.current_char and self.current_char == ")" then self:advance() return Token:new(RPAREN,")") end - self:error("Invalid Symbol!") + if self.current_char and self.current_char:match("%w") then + return self:_id() + end + if self.current_char and self.current_char == ":" and self:peek() == "=" then + self:advance() + self:advance() + return Token:new(ASSIGN, ":=") + end + if self.current_char and self.current_char == ";" then + self:advance() + return Token:new(SEMI, ';') + end + if self.current_char and self.current_char == "." then + self:advance() + return Token:new(DOT,".") + end + if self.current_char == false then + return Token:new(EOF, "EOF") + end + self:error("Invalid Symbol! "..tostring(self.current_char)) end - return Token:new(EOF, nil) + return Token:new(EOF, "EOF") end -Interpreter = {} -Interpreter.__index = Interpreter -function Interpreter:new(lexer) +AST = {} +AST.__index = AST +function AST:new() local c = {} setmetatable(c,self) - c.lexer = lexer - c.current_token = c.lexer:get_next_token() + c.Type = 'AST' return c end -function Interpreter:error() + +Compound = {} +Compound.__index = AST +function Compound:new() + local c = {} + setmetatable(c,self) + c.Type = 'Compound' + c.children = {} + return c +end + +Assign = {} +Assign.__index = AST +function Assign:new(left,op,right) + local c = {} + setmetatable(c,self) + c.Type = 'Assign' + c.left = left + c.op = op + c.token = op + c.right = right + return c +end + +Var = {} +Var.__index = AST +function Var:new(token) + local c = {} + setmetatable(c,self) + c.Type = "Var" + c.token = token + c.value = token.value + return c +end + +NoOp = {} +NoOp.__index = AST +function NoOp:new() + local c = {} + setmetatable(c,self) + c.Type = "NoOp" + return c +end + +UnaryOp = {} +UnaryOp.__index = AST +function UnaryOp:new(op,expr) + local c = {} + setmetatable(c,self) + c.Type = 'UnaryOp' + c.token = op + c.op = op + c.expr = expr + return c +end + +BinOp = {} +BinOp.__index = AST +function BinOp:new(left, op, right) + local c = {} + setmetatable(c,self) + c.Type = 'BinOp' + c.left = left + c.token = op + c.op = op + c.right = right + return c +end + +Num = {} +Num.__index = AST +function Num:new(token) + local c = {} + setmetatable(c,self) + c.Type = 'Num' + c.token = token + c.value = token.value + return c +end + +Parser = {} +Parser.__index = Parser +function Parser:new(lexer) + local c = {} + setmetatable(c,self) + c.Type = 'Parser' + c.lexer = lexer + c.current_token = lexer:get_next_token() + return c +end +function Parser:error() error('Error Invalid Syntax') end -function Interpreter:eat(token_type) +function Parser:eat(token_type) if self.current_token.type == token_type then self.current_token = self.lexer:get_next_token() else self:error() end end -function Interpreter:factor() +function Parser:program() + local node = self:compound_statement() + self:eat(DOT) + return node +end +function Parser:compound_statement() + self:eat(BEGIN) + local nodes = self:statement_list() + self:eat(END) + + local root = Compound:new() + for _,node in pairs(nodes) do + table.insert(root.children,node) + end + + return root +end +function Parser:statement_list() + local node = self:statement() + + local results = {node} + + while self.current_token.type == SEMI do + self:eat(SEMI) + table.insert(results,self:statement()) + end + + if self.current_token.type == ID then + self:error() + end + + return results +end +function Parser:statement() + local node + if self.current_token.type == BEGIN then + node = self:compound_statement() + elseif self.current_token.type == ID then + node = self:assignment_statement() + else + node = self:empty() + end + return node +end +function Parser:assignment_statement() + local left = self:variable() local token = self.current_token - if token.type == INTEGER then + self:eat(ASSIGN) + local right = self:expr() + local node = Assign:new(left, token, right) + return node +end +function Parser:variable() + local node = Var:new(self.current_token) + self:eat(ID) + return node +end +function Parser:empty() + return NoOp:new() +end +function Parser:factor() + local token = self.current_token + local node + if token.type == PLUS then + self:eat(PLUS) + node = UnaryOp:new(token,self:factor()) + return node + elseif token.type == MINUS then + self:eat(MINUS) + node = UnaryOp:new(token,self:factor()) + return node + elseif token.type == INTEGER then self:eat(INTEGER) - return token.value + return Num:new(token) elseif token.type == LPAREN then self:eat(LPAREN) - local result = self:expr() + local node = self:expr() self:eat(RPAREN) - return result + return node + else + node = self:variable() + return node end end -function Interpreter:term() - local result = self:factor() +function Parser:term() + local node = self:factor() local token while self.current_token.type == MUL or self.current_token.type == DIV do token = self.current_token if token.type == MUL then self:eat(MUL) - result = result * self:factor() elseif token.type == DIV then self:eat(DIV) - result = result / self:factor() end + node = BinOp:new(node,token,self:factor()) end - return result + + return node end -function Interpreter:expr() - local result = self:term() +function Parser:expr() + local node = self:term() local token while self.current_token.type == PLUS or self.current_token.type == MINUS do token = self.current_token if token.type == PLUS then self:eat(PLUS) - result = result + self:term() elseif token.type == MINUS then self:eat(MINUS) - result = result - self:term() + end + node = BinOp:new(node,token,self:term()) + end + + return node +end +function Parser:parse() + local node = self:program() + if self.current_token.type ~= EOF then + self:error() + end + return node +end + +NodeVisitor = {} +NodeVisitor.__index = NodeVisitor +function NodeVisitor:new(node) + local c = {} + setmetatable(c,self) + c.Type = 'NodeVisitor' + return c +end +function NodeVisitor:visit(node) + local visitor = self["visit_".. node.Type] or self.generic_visit + return visitor(self,node) +end +function NodeVisitor:generic_visit(node) + error("No visit_"..node.Type.." method") +end + +Interpreter = {} +Interpreter.__index = NodeVisitor +function Interpreter:new(parser) + local c = {} + setmetatable(c,self) + c.Type = 'Interpreter' + c.parser = parser + c.GLOBAL_SCOPE = {} + function c:visit_Compound(node) + for _,child in pairs(node.children) do + self:visit(child) end end - return result -end -while true do - io.write("calc> ") - local text = io.read() - if text then - l = Lexer:new(text) - i = Interpreter:new(l) - result = i:expr() - print(result) + function c:visit_Assign(node) + local var_name = node.left.value + self.GLOBAL_SCOPE[var_name] = self:visit(node.right) end + function c:visit_Var(node) + local var_name = node.value + local val = self.GLOBAL_SCOPE[var_name] + if val then + return val + else + error("NameError:"..var_name) + end + end + function c:visit_NoOp(node) + return + end + function c:visit_BinOp(node) + if node.op.type == PLUS then + return self:visit(node.left) + self:visit(node.right) + elseif node.op.type == MINUS then + return self:visit(node.left) - self:visit(node.right) + elseif node.op.type == MUL then + return self:visit(node.left) * self:visit(node.right) + elseif node.op.type == DIV then + return self:visit(node.left) / self:visit(node.right) + end + end + function c:visit_UnaryOp(node) + local op = node.op.type + if op == PLUS then + return self:visit(node.expr) + elseif op == MINUS then + return -self:visit(node.expr) + end + end + function c:visit_Num(node) + return node.value + end + function c:interpret() + local tree = self.parser:parse() + return self:visit(tree) + end + return c end + +text = [[ +BEGIN + BEGIN + number := 2; + a := number; + b := 10 * a + 10 * number / 4; + c := a - - b + END; + x := 11; +END. +]] +lexer = Lexer:new(text) +parser = Parser:new(lexer) +interpreter = Interpreter:new(parser) +tprint(parser) +-- interpreter:interpret() +-- for i,v in pairs(interpreter.GLOBAL_SCOPE) do +-- print(i,v) +-- end +-- while true do +-- io.write("calc> ") +-- local text = io.read() +-- if text then +-- lexer = Lexer:new(text) +-- parser = Parser:new(lexer) +-- interpreter = Interpreter:new(parser) +-- result = interpreter:interpret() +-- print(result) +-- end +-- end diff --git a/compiler2.lua b/compiler2.lua new file mode 100644 index 0000000..9c5a90a --- /dev/null +++ b/compiler2.lua @@ -0,0 +1,28 @@ +file = io.open("test.dms","rb") +content = file:read("*a") +line_num = 0 +function string:trim() + return (self:gsub("^%s*(.-)%s*$", "%1")) +end +local choice +for line in content:gmatch("(.-)\n") do + line_num = line_num + 1 + line = line:trim() + ::back:: + if line:match("^%[[_:,%w%(%)]+%]") then + print(line_num,"BLOCK_START",line) + elseif line:match("choice%s+\".+\"%s*:") then + print(line_num,"CHOICE_BLOCK",line) + choice = true + elseif choice then + choice = false + if line:match("\".*\"%s*[_:,%w%(%)]+%(.*%)") then + print(line_num,"CHOICE_OPTION",line) + choice = true + else + goto back + end + else + print(line_num,line) + end +end \ No newline at end of file diff --git a/test.dms b/test.dms index 3fa339e..87472cb 100644 --- a/test.dms +++ b/test.dms @@ -10,8 +10,11 @@ LOADFILE Ryan: "Hello how are you doing?" Bob: "I'm good you?" - list = {1,2,3,true,false, {1,2,3}} + a = list[1] + list[1] = "Hello" + + ::label:: choice "Pick one:": "first" func()