Parser can parse more commands
This commit is contained in:
parent
bee1d90bf1
commit
a6a16e614a
64
DMS.xml
Normal file
64
DMS.xml
Normal file
@ -0,0 +1,64 @@
|
||||
<NotepadPlus>
|
||||
<UserLang name="DMS" ext="dms" udlVersion="2.1">
|
||||
<Settings>
|
||||
<Global caseIgnored="no" allowFoldOfComments="yes" foldCompact="no" forcePureLC="0" decimalSeparator="2" />
|
||||
<Prefix Keywords1="no" Keywords2="no" Keywords3="no" Keywords4="no" Keywords5="no" Keywords6="no" Keywords7="no" Keywords8="no" />
|
||||
</Settings>
|
||||
<KeywordLists>
|
||||
<Keywords name="Comments">00// 01 02 03/* 04*/</Keywords>
|
||||
<Keywords name="Numbers, prefix1"></Keywords>
|
||||
<Keywords name="Numbers, prefix2"></Keywords>
|
||||
<Keywords name="Numbers, extras1"></Keywords>
|
||||
<Keywords name="Numbers, extras2"></Keywords>
|
||||
<Keywords name="Numbers, suffix1"></Keywords>
|
||||
<Keywords name="Numbers, suffix2"></Keywords>
|
||||
<Keywords name="Numbers, range"></Keywords>
|
||||
<Keywords name="Operators1">+ - * / = ( ) [ ] , > < ~ ! | ; :</Keywords>
|
||||
<Keywords name="Operators2"></Keywords>
|
||||
<Keywords name="Folders in code1, open">{</Keywords>
|
||||
<Keywords name="Folders in code1, middle"></Keywords>
|
||||
<Keywords name="Folders in code1, close">}</Keywords>
|
||||
<Keywords name="Folders in code2, open"></Keywords>
|
||||
<Keywords name="Folders in code2, middle"></Keywords>
|
||||
<Keywords name="Folders in code2, close"></Keywords>
|
||||
<Keywords name="Folders in comment, open">/*</Keywords>
|
||||
<Keywords name="Folders in comment, middle"></Keywords>
|
||||
<Keywords name="Folders in comment, close">*/</Keywords>
|
||||
<Keywords name="Keywords1">ENABLE DISABLE LOADFILE ENTRY USING VERSION as AS enable disable loadfile entry using version</Keywords>
|
||||
<Keywords name="Keywords2">if then return and or true false for while choice end else elseif goto</Keywords>
|
||||
<Keywords name="Keywords3">leaking debugging warnings statesave hostmsg</Keywords>
|
||||
<Keywords name="Keywords4">ceil tan CSIM log10 sinh GOTOE lshift deg MUL QUIT cosh exp rad GOTO SUB log ADD JUMP error POW randomseed floor tanh max atan SKIP acos DIV abs rshif COMPARE print atan2 asin cos sin mod sqrt function getInput sleep getVar setVar newThread setGlobalVar getGlobalVar SAVE LOAD WATCH env</Keywords>
|
||||
<Keywords name="Keywords5">_VERSION</Keywords>
|
||||
<Keywords name="Keywords6">filesystem extendedDefine</Keywords>
|
||||
<Keywords name="Keywords7"></Keywords>
|
||||
<Keywords name="Keywords8"></Keywords>
|
||||
<Keywords name="Delimiters">00:: 01 02:: 03$ 04 05$ 06" 07 08" 09 10 11 12' 13 14' 15 16 17 18 19 20 21 22 23</Keywords>
|
||||
</KeywordLists>
|
||||
<Styles>
|
||||
<WordsStyle name="DEFAULT" fgColor="C3C3C3" bgColor="293135" fontName="Monospac821 BT" fontStyle="0" fontSize="12" nesting="0" />
|
||||
<WordsStyle name="COMMENTS" fgColor="808080" bgColor="293134" fontName="Monospac821 BT" fontStyle="0" fontSize="12" nesting="0" />
|
||||
<WordsStyle name="LINE COMMENTS" fgColor="808080" bgColor="293134" fontName="Monospac821 BT" fontStyle="0" fontSize="12" nesting="0" />
|
||||
<WordsStyle name="NUMBERS" fgColor="FF8080" bgColor="293134" fontName="Monospac821 BT" fontStyle="0" fontSize="12" nesting="0" />
|
||||
<WordsStyle name="KEYWORDS1" fgColor="FF8000" bgColor="293134" fontName="Monospac821 BT" fontStyle="1" fontSize="12" nesting="0" />
|
||||
<WordsStyle name="KEYWORDS2" fgColor="0080C0" bgColor="293134" fontName="Monospac821 BT" fontStyle="1" fontSize="12" nesting="0" />
|
||||
<WordsStyle name="KEYWORDS3" fgColor="408080" bgColor="293134" fontName="Monospac821 BT" fontStyle="1" fontSize="12" nesting="0" />
|
||||
<WordsStyle name="KEYWORDS4" fgColor="5959AC" bgColor="293134" fontName="Monospac821 BT" fontStyle="1" fontSize="12" nesting="0" />
|
||||
<WordsStyle name="KEYWORDS5" fgColor="FF0080" bgColor="293134" fontName="Monospac821 BT" fontStyle="0" fontSize="12" nesting="0" />
|
||||
<WordsStyle name="KEYWORDS6" fgColor="149311" bgColor="293134" fontName="" fontStyle="1" fontSize="12" nesting="0" />
|
||||
<WordsStyle name="KEYWORDS7" fgColor="0080C0" bgColor="293134" fontName="" fontStyle="1" fontSize="12" nesting="0" />
|
||||
<WordsStyle name="KEYWORDS8" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="0" nesting="0" />
|
||||
<WordsStyle name="OPERATORS" fgColor="EAC195" bgColor="293134" fontName="Monospac821 BT" fontStyle="1" nesting="0" />
|
||||
<WordsStyle name="FOLDER IN CODE1" fgColor="EAC195" bgColor="293134" fontName="Monospac821 BT" fontStyle="1" fontSize="12" nesting="0" />
|
||||
<WordsStyle name="FOLDER IN CODE2" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="0" nesting="0" />
|
||||
<WordsStyle name="FOLDER IN COMMENT" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="0" nesting="0" />
|
||||
<WordsStyle name="DELIMITERS1" fgColor="8080C0" bgColor="293134" fontName="Monospac821 BT" fontStyle="1" fontSize="12" nesting="0" />
|
||||
<WordsStyle name="DELIMITERS2" fgColor="808040" bgColor="293134" fontName="Monospac821 BT" fontStyle="0" fontSize="12" nesting="0" />
|
||||
<WordsStyle name="DELIMITERS3" fgColor="FFA346" bgColor="293134" fontName="Monospac821 BT" fontStyle="0" fontSize="12" nesting="0" />
|
||||
<WordsStyle name="DELIMITERS4" fgColor="408080" bgColor="293134" fontName="" fontStyle="1" nesting="0" />
|
||||
<WordsStyle name="DELIMITERS5" fgColor="FFA346" bgColor="293134" fontName="" fontStyle="0" nesting="0" />
|
||||
<WordsStyle name="DELIMITERS6" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="0" nesting="0" />
|
||||
<WordsStyle name="DELIMITERS7" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="0" nesting="0" />
|
||||
<WordsStyle name="DELIMITERS8" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="0" nesting="0" />
|
||||
</Styles>
|
||||
</UserLang>
|
||||
</NotepadPlus>
|
||||
141
compiler2.lua
141
compiler2.lua
@ -1,137 +1,4 @@
|
||||
file = io.open("test.dms","rb")
|
||||
content = file:read("*a")
|
||||
line_num = 0
|
||||
CMD = {}
|
||||
CMD.__index = CMD
|
||||
function CMD:new(ln,cmd,args)
|
||||
local c = {}
|
||||
setmetatable(c,self)
|
||||
c.line_num = ln
|
||||
c.command = cmd
|
||||
c.args = args
|
||||
end
|
||||
function CMD:process()
|
||||
|
||||
end
|
||||
Stack = {}
|
||||
Stack.__index = Stack
|
||||
function Stack.__tostring(self)
|
||||
return table.concat(self.stack, ", ")
|
||||
end
|
||||
function Stack:new(n)
|
||||
local c = {}
|
||||
setmetatable(c,self)
|
||||
c.max = n or math.huge
|
||||
c.stack = {}
|
||||
return c
|
||||
end
|
||||
function Stack:push(n)
|
||||
table.insert(self.stack,n)
|
||||
end
|
||||
function Stack:pop()
|
||||
return table.remove(self.stack,#self.stack)
|
||||
end
|
||||
function Stack:peek(n)
|
||||
return self.stack[#self.stack - (n or 0)]
|
||||
end
|
||||
function Stack:count()
|
||||
return #self.stack
|
||||
end
|
||||
|
||||
function string:trim()
|
||||
return (self:gsub("^%s*(.-)%s*$", "%1"))
|
||||
end
|
||||
function string.tabs(str)
|
||||
local c = 0
|
||||
for i in str:gmatch(".") do
|
||||
if i=="\t" then
|
||||
c=c+1
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
return c
|
||||
end
|
||||
local choice
|
||||
local group = 0
|
||||
local lastgroup = 0
|
||||
local groupStack = Stack:new({})
|
||||
local lastpop
|
||||
groupStack:push({})
|
||||
function groupStack:append(t)
|
||||
local c = self:peek()
|
||||
val = pcall(function()
|
||||
table.insert(c,t)
|
||||
end)
|
||||
if not val then
|
||||
error("Inconsistant indentation!")
|
||||
end
|
||||
end
|
||||
local noblock = true
|
||||
for line in content:gmatch("(.-)\n") do
|
||||
line_num = line_num + 1
|
||||
--line = line:trim()
|
||||
--line = line:gsub("")
|
||||
lastgroup = group
|
||||
group = line:tabs()
|
||||
if lastgroup>group then
|
||||
for i=1,lastgroup-group do
|
||||
local c = groupStack:pop()
|
||||
lastpop = c
|
||||
for i,v in pairs(c) do
|
||||
print(table.concat(v,", "))
|
||||
end
|
||||
end
|
||||
elseif lastgroup<group then
|
||||
groupStack:push({})
|
||||
end
|
||||
if line=="" then goto continue end
|
||||
::back::
|
||||
if line:trim()=="" then
|
||||
goto continue
|
||||
elseif line:match("^%[[_:,%w%(%)]+%]") then
|
||||
groupStack:append{group,line_num,"<BLOCK_START>",line}
|
||||
noblock = false
|
||||
-- We gonna define header stuff
|
||||
elseif noblock and line:lower():match("enable%s(.+)") then
|
||||
groupStack:append{group,line_num,"<ENABLE>",line}
|
||||
elseif noblock and line:lower():match("disable%s(.+)") then
|
||||
groupStack:append{group,line_num,"<DISABLE>",line}
|
||||
elseif noblock and line:lower():match("loadfile%s(.+)") then
|
||||
groupStack:append{group,line_num,"<LOADFILE>",line}
|
||||
elseif noblock and line:lower():match("entry%s(.+)") then
|
||||
groupStack:append{group,line_num,"<ENTRY>",line}
|
||||
elseif noblock and line:lower():match("using%s(.+)") then
|
||||
groupStack:append{group,line_num,"<USING>",line}
|
||||
elseif noblock and line:lower():match("version%s(.+)") then
|
||||
groupStack:append{group,line_num,"<VERSION>",line}
|
||||
elseif line:match("choice%s+\".+\"") then
|
||||
groupStack:append{group,line_num,"<CHOICE_BLOCK>",line}
|
||||
choice = true
|
||||
elseif line:match("::([_:,%w%(%)]+)::") then
|
||||
groupStack:append{group,line_num,"<LABEL_BLOCK>",line}
|
||||
elseif line:match("for%s*[_%w]-%s") then
|
||||
groupStack:append{group,line_num,"<FOR_BLOCK>",line}
|
||||
elseif line:match("%s*while%s*.+") then
|
||||
groupStack:append{group,line_num,"<WHILE_BLOCK>",line}
|
||||
elseif choice then
|
||||
choice = false
|
||||
if line:match("\".*\"%s*[_:,%w%(%)]+%(.*%)") then
|
||||
groupStack:append{group,line_num,"<CHOICE_OPTION>",line}
|
||||
choice = true
|
||||
else
|
||||
goto back
|
||||
end
|
||||
elseif line:match("[%s,_%w]*=.-%(.+%)") then
|
||||
groupStack:append{group,line_num,"<FUNCWR>",line}
|
||||
elseif line:match(".-%(.+%)") then
|
||||
groupStack:append{group,line_num,"<FUNCNR>",line}
|
||||
elseif line:match("[%s,_%w]*=(.+)") then
|
||||
groupStack:append{group,line_num,"<ASSIGNMENT>",line}
|
||||
elseif line:match("\"(.+)\"") then
|
||||
groupStack:append{group,line_num,"<DISP_MSG>",line}
|
||||
else
|
||||
groupStack:append{group,line_num,"<UNKNOWN_BLOCK>",line}
|
||||
end
|
||||
::continue::
|
||||
end
|
||||
package.path="?.lua;?/init.lua;?.lua;?/?/init.lua;"..package.path
|
||||
local parser = require("dms.parser")
|
||||
local p = parser:new("test.dms")
|
||||
p:parse()
|
||||
|
||||
33
dms/chunk.lua
Normal file
33
dms/chunk.lua
Normal file
@ -0,0 +1,33 @@
|
||||
local cmd = require("dms.cmd")
|
||||
local Chunk = {}
|
||||
Chunk.__index = Chunk
|
||||
function Chunk:__tostring()
|
||||
local str = self.chunkname..":"..self.chunktype.."\n"
|
||||
local s = ""
|
||||
for i,v in pairs(self.cmds) do
|
||||
str = str .. tostring(v).."\n"
|
||||
end
|
||||
return str
|
||||
end
|
||||
function Chunk:new(cname,ctype,filename)
|
||||
local c = {}
|
||||
setmetatable(c,self)
|
||||
c.chunkname = cname
|
||||
c.chunktype = ctype
|
||||
c.filename = filename
|
||||
c.pos = 0
|
||||
c.cmds = {}
|
||||
c.labels = {} -- ["label"] = pos
|
||||
return c
|
||||
end
|
||||
function Chunk:addLabel(label)
|
||||
self.labels[label] = self:count()
|
||||
end
|
||||
function Chunk:addCmd(cmd)
|
||||
cmd.chunk = self
|
||||
table.insert(self.cmds,cmd)
|
||||
end
|
||||
function Chunk:count()
|
||||
return #self.cmds
|
||||
end
|
||||
return Chunk
|
||||
15
dms/cmd.lua
Normal file
15
dms/cmd.lua
Normal file
@ -0,0 +1,15 @@
|
||||
local CMD = {}
|
||||
CMD.__index = CMD
|
||||
CMD.tostring = function(self) return self.command end
|
||||
function CMD:__tostring()
|
||||
return self.command .. " " .. self:tostring()
|
||||
end
|
||||
function CMD:new(line,cmd,args)
|
||||
local c = {}
|
||||
setmetatable(c,self)
|
||||
c.line = line
|
||||
c.command = cmd
|
||||
c.args = args
|
||||
return c
|
||||
end
|
||||
return CMD
|
||||
0
dms/init.lua
Normal file
0
dms/init.lua
Normal file
335
dms/parser.lua
Normal file
335
dms/parser.lua
Normal file
@ -0,0 +1,335 @@
|
||||
require("dms.utils")
|
||||
local Stack = require("dms.stack")
|
||||
local Chunk = require("dms.chunk")
|
||||
local Cmd = require("dms.cmd")
|
||||
local ENTR,ENAB,DISA,LOAD,VERN,USIN,STAT,DISP,ASGN,LABL,CHOI,OPTN,FORE,UNWN,WHLE,FNWR,FNNR,IFFF,ELIF,ELSE,DEFN = "ENTR","ENAB","DISA","LOAD","VERN","USIN","STAT","DISP","ASGN","LABL","CHOI","OPTN","FORE","????","WHLE","FNWR","FNNR","IFFF","ELIF","ELSE","DEFN"
|
||||
local controls = {STAT,CHOI,FORE,WHLE,IFFF,ELIF,ELSE}
|
||||
local flags = {ENTR,ENAB,DISA,LOAD,VERN,USIN,DEFN}
|
||||
local recognizedFlags = {
|
||||
"debugging",
|
||||
"noprint",
|
||||
"warnings"
|
||||
}
|
||||
local parser = {}
|
||||
parser.__index = parser
|
||||
function parser:new(path)
|
||||
local c = {}
|
||||
setmetatable(c,self)
|
||||
c.filename = path or error("Must provied a path!")
|
||||
c.content = io.open(c.filename,"rb"):read("*a")
|
||||
c.flags = {}
|
||||
c.chunks = {}
|
||||
c.ver = {1,0,0}
|
||||
c.pos = 0
|
||||
c.lines = {}
|
||||
return c
|
||||
end
|
||||
function parser:setVersion(ver)
|
||||
self.ver = ver
|
||||
end
|
||||
-- Output Stuffs
|
||||
function parser:debug(...)
|
||||
if not self.flags.debugging then return end
|
||||
self:print(...)
|
||||
end
|
||||
function parser:print(...)
|
||||
if self.flags.noprint then return end
|
||||
print(...)
|
||||
end
|
||||
function parser:error(err,line)
|
||||
if not line then print(err) os.exit() end
|
||||
print("Error: <"..line[4]..":"..line[1].."> \""..line[5].."\" "..err)
|
||||
os.exit()
|
||||
end
|
||||
function parser:warn(msg,line)
|
||||
if not self.flags.warnings then return end
|
||||
if not line then print(msg) return end
|
||||
print("Warning: <"..line[4]..":"..line[1].."> \""..line[5].."\" "..msg)
|
||||
end
|
||||
|
||||
function parser:manageFlag(line)
|
||||
if self:isFlag(line) then
|
||||
local flag = line[3]
|
||||
local dat = line[5]:match("%s+(.+)$")
|
||||
if flag == ENTR then
|
||||
if self.entry then
|
||||
self:error("Entry was already set to: "..self.entry,line)
|
||||
else
|
||||
self.entry = dat
|
||||
end
|
||||
elseif flag == ENAB then
|
||||
if not self:isRecognizedFlag(dat) then self:warn("Flag \""..dat.."\" is not recognized!",line) end
|
||||
self.flags[dat] = true
|
||||
elseif flag == DISA then
|
||||
if not self:isRecognizedFlag(dat) then self:warn("Flag \""..dat.."\" is not recognized!",line) end
|
||||
self.flags[dat] = false
|
||||
elseif flag == LOAD then
|
||||
-- TODO
|
||||
elseif flag == VERN then
|
||||
local v
|
||||
local a,b,c = dat:match("(%d*)%.?(%d*)%.?(%d*)")
|
||||
a,b,c = tonumber(a),tonumber(b) or 0,tonumber(c) or 0
|
||||
if a>self.ver[1] or a>self.ver[2] then
|
||||
self:warn("This script was created for a different version of the DMS! Code may behave unexpectedly or not work at all!",line)
|
||||
end
|
||||
elseif flag == USIN then
|
||||
-- TODO
|
||||
end
|
||||
else
|
||||
self:error("Flag Expected! Got: "..line[3],line)
|
||||
end
|
||||
end
|
||||
function parser:isControl(line)
|
||||
for i,v in pairs(controls) do
|
||||
if line[3] == v then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
function parser:isFlag(line)
|
||||
for i,v in pairs(flags) do
|
||||
if line[3] == v then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
function parser:isRecognizedFlag(flag)
|
||||
for i,v in pairs(recognizedFlags) do
|
||||
if v == flag:lower() then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
function parser:parse()
|
||||
local link = self
|
||||
local line_num = 0
|
||||
local choice
|
||||
local group = 0
|
||||
local lastgroup = 0
|
||||
local groupStack = Stack:new({})
|
||||
local lastpop
|
||||
local noblock = true
|
||||
local arr = {}
|
||||
local multilined = false
|
||||
function groupStack:append(t)
|
||||
local c = self:peek()
|
||||
val = pcall(function()
|
||||
table.insert(c,1,t)
|
||||
end)
|
||||
if not val then
|
||||
link:error("Inconsistant indentation!",t)
|
||||
end
|
||||
end
|
||||
groupStack:push({})
|
||||
for line in self.content:gmatch("(.-)\n") do
|
||||
line_num = line_num + 1
|
||||
line = line:gsub("//(.+)$","") -- Filter out comments
|
||||
if not multilined and line:match("/%*(.+)$") then
|
||||
multilined = true
|
||||
line = line:gsub("/%*(.*)$","")
|
||||
end
|
||||
if multilined then
|
||||
if line:match("%*/") then
|
||||
multilined = false
|
||||
line = line:gsub("(.+)%*/","")
|
||||
if #line:trim() == 0 then
|
||||
goto continue
|
||||
end
|
||||
else
|
||||
goto continue
|
||||
end
|
||||
end
|
||||
if line:trim()=="" then goto continue end -- Skip all whitespace completely
|
||||
lastgroup = group
|
||||
group = line:tabs()
|
||||
if lastgroup>group then
|
||||
for i=1,lastgroup-group do
|
||||
local c = groupStack:pop()
|
||||
lastpop = c
|
||||
for i,v in pairs(c) do
|
||||
table.insert(arr,v)
|
||||
end
|
||||
end
|
||||
elseif lastgroup<group then
|
||||
groupStack:push({})
|
||||
end
|
||||
if line=="" then goto continue end
|
||||
::back::
|
||||
if line:match("^%[[_:,%w%(%)]+%]") then
|
||||
groupStack:append{line_num,group,STAT,self.filename,line:trim()}
|
||||
noblock = false
|
||||
-- We gonna define header stuff
|
||||
elseif noblock and line:lower():match("enable%s(.+)") then
|
||||
groupStack:append{line_num,group,ENAB,self.filename,line:trim()}
|
||||
elseif noblock and line:lower():match("disable%s(.+)") then
|
||||
groupStack:append{line_num,group,DISA,self.filename,line:trim()}
|
||||
elseif noblock and line:lower():match("loadfile%s(.+)") then
|
||||
groupStack:append{line_num,group,LOAD,self.filename,line:trim()}
|
||||
elseif noblock and line:lower():match("entry%s(.+)") then
|
||||
groupStack:append{line_num,group,ENTR,self.filename,line:trim()}
|
||||
elseif noblock and line:lower():match("using%s(.+)") then
|
||||
groupStack:append{line_num,group,USIN,self.filename,line:trim()}
|
||||
elseif noblock and line:lower():match("version%s(.+)") then
|
||||
groupStack:append{line_num,group,VERN,self.filename,line:trim()}
|
||||
elseif line:match("choice%s+\".+\"") then
|
||||
groupStack:append{line_num,group,CHOI,self.filename,line:trim()}
|
||||
choice = true
|
||||
elseif line:match("::([_:,%w%(%)]+)::") then
|
||||
groupStack:append{line_num,group,LABL,self.filename,line:trim()}
|
||||
elseif line:match("for%s*[_%w]-%s") then
|
||||
groupStack:append{line_num,group,FORE,self.filename,line:trim()}
|
||||
elseif line:match("%s*while%s*.+") then
|
||||
groupStack:append{line_num,group,WHLE,self.filename,line:trim()}
|
||||
elseif choice then
|
||||
choice = false
|
||||
if line:match("\".*\"%s*[_:,%w%(%)]+%(.*%)") then
|
||||
groupStack:append{line_num,group,OPTN,self.filename,line:trim()}
|
||||
choice = true
|
||||
else
|
||||
goto back
|
||||
end
|
||||
elseif line:match("[%s,_%w]*=.-%(.+%)") then
|
||||
groupStack:append{line_num,group,FNWR,self.filename,line:trim()}
|
||||
elseif line:match(".-%(.+%)") then
|
||||
groupStack:append{line_num,group,FNNR,self.filename,line:trim()}
|
||||
elseif line:match("[%s,_%w]*=(.+)") then
|
||||
groupStack:append{line_num,group,ASGN,self.filename,line:trim()}
|
||||
elseif line:match("\"(.+)\"") then
|
||||
groupStack:append{line_num,group,DISP,self.filename,line:trim()}
|
||||
elseif line:match("elseif%s*(.+)") then
|
||||
groupStack:append{line_num,group,ELIF,self.filename,line:trim()}
|
||||
elseif line:match("if%s*(.+)") then
|
||||
groupStack:append{line_num,group,IFFF,self.filename,line:trim()}
|
||||
elseif line:match("else%s*(.+)") then
|
||||
groupStack:append{line_num,group,ELSE,self.filename,line:trim()}
|
||||
else
|
||||
groupStack:append{line_num,group,UNWN,self.filename,line:trim()}
|
||||
end
|
||||
::continue::
|
||||
end
|
||||
-- Final Pop
|
||||
for i = 1,groupStack:count() do
|
||||
local c = groupStack:pop()
|
||||
for i,v in pairs(c) do
|
||||
table.insert(arr,v)
|
||||
end
|
||||
end
|
||||
table.sort(arr,function(k1,k2)
|
||||
return k1[1]<k2[1]
|
||||
end)
|
||||
self.lines = arr
|
||||
local chunks = {}
|
||||
local handler = Stack:new()
|
||||
local v = self:next()
|
||||
while v ~= nil do
|
||||
if self:isFlag(v) then
|
||||
self:manageFlag(v)
|
||||
elseif self:isControl(v) then
|
||||
if v[3] == STAT then
|
||||
print("BLOCK",table.concat(v,"\t"))
|
||||
if self.current_chunk then
|
||||
chunks[self.current_chunk.chunkname] = self.current_chunk
|
||||
end
|
||||
local cname,ctype = v[5]:match("%[(%w+):*(.-)%]")
|
||||
if #ctype == 0 then ctype = "block" end
|
||||
self:debug("Registering Block: \""..cname.."\" type: \""..(ctype:match("(.+)%(") or ctype).."\"")
|
||||
self.current_chunk = Chunk:new(cname,ctype,v[4])
|
||||
if chunks[cname] then self:error("Chunk \""..cname.."\" has already been defined!",v) end
|
||||
elseif v[3] == CHOI then
|
||||
self:parseChoice(v)
|
||||
else
|
||||
--print("CTRL",table.concat(v,"\t"))
|
||||
end
|
||||
else
|
||||
if v[3] == DISP then
|
||||
self:parseDialogue(v)
|
||||
elseif v[3] == FNNR then
|
||||
self:parseFNNR(v)
|
||||
elseif v[3] == FNWR then
|
||||
self:parseFNWR(v)
|
||||
elseif v[3] == ASGN then
|
||||
self:parseASGN(v)
|
||||
elseif v[3] == LABL then
|
||||
self.current_chunk:addLabel(v[5]:match("::(.+)::"))
|
||||
end
|
||||
--print("FUNC",table.concat(v,"\t"))
|
||||
end
|
||||
v = self:next()
|
||||
end
|
||||
if current_chunk then
|
||||
chunks[current_chunk.chunkname] = current_chunk
|
||||
end
|
||||
for i,v in pairs(chunks) do
|
||||
print(i,v)
|
||||
end
|
||||
end
|
||||
function parser:parseFNNR(line)
|
||||
local fname, args = line[5]:match("(.-)%((.+)%)")
|
||||
args = args:split()
|
||||
local cmd = Cmd:new(line,FNNR,{func=fname,args=args})
|
||||
function cmd:tostring()
|
||||
return table.concat({fname,table.concat(args,", ")},", ")
|
||||
end
|
||||
self.current_chunk:addCmd(cmd)
|
||||
end
|
||||
function parser:parseFNWR(line)
|
||||
local vars, fname, args = line[5]:match("(.-)%s*=%s*(.-)%((.+)%)")
|
||||
vars = vars:split()
|
||||
args = args:split()
|
||||
local cmd = Cmd:new(line,FNWR,{func=fname,args=args,vars=vars})
|
||||
function cmd:tostring()
|
||||
return table.concat({fname,table.concat(args,", ")},", ").." -> ".. table.concat(vars,", ")
|
||||
end
|
||||
self.current_chunk:addCmd(cmd)
|
||||
end
|
||||
function parser:parseASGN(line)
|
||||
local vars,assigns = line[5]:match("(.-)%s*=%s*(.+)")
|
||||
vars = vars:split()
|
||||
assigns = assigns:split()
|
||||
local cmd = Cmd:new(line,ASGN,{vars = vars, assigns = assigns})
|
||||
function cmd:tostring()
|
||||
return "DATA -> "..table.concat(vars,", ")
|
||||
end
|
||||
self.current_chunk:addCmd(cmd)
|
||||
-- TODO: make dict lookups builtin
|
||||
end
|
||||
function parser:parseChoice(line)
|
||||
local text = line[5]:match("\"(.+)\"")
|
||||
local copt = self:peek()
|
||||
local choice = {text = text}
|
||||
local cmd = Cmd:new(line,CHOI,choice)
|
||||
if copt[3]~=OPTN then
|
||||
self:error("Choices must have at least one option to choose!")
|
||||
return
|
||||
end
|
||||
while copt do
|
||||
copt = self:next()
|
||||
local a,b = copt[5]:match("(.+) %s*(.+)")
|
||||
print(a,"|",b)
|
||||
copt = self:peek()
|
||||
if copt[3]~=OPTN then
|
||||
break
|
||||
end
|
||||
end
|
||||
-- We need to get functions working first
|
||||
end
|
||||
function parser:parseDialogue(line)
|
||||
local targ,text = line[5]:match("(%w*)%s*(.*)")
|
||||
if #targ == 0 then targ = nil end
|
||||
local cmd = Cmd:new(line,DISP,{text=text,target=targ})
|
||||
function cmd:tostring()
|
||||
return table.concat({targ or "@",text},", ")
|
||||
end
|
||||
self.current_chunk:addCmd(cmd)
|
||||
end
|
||||
function parser:peek()
|
||||
return self.lines[self.pos + 1]
|
||||
end
|
||||
function parser:next()
|
||||
self.pos = self.pos + 1
|
||||
return self.lines[self.pos]
|
||||
end
|
||||
return parser
|
||||
25
dms/stack.lua
Normal file
25
dms/stack.lua
Normal file
@ -0,0 +1,25 @@
|
||||
local Stack = {}
|
||||
Stack.__index = Stack
|
||||
function Stack.__tostring(self)
|
||||
return table.concat(self.stack, ", ")
|
||||
end
|
||||
function Stack:new(n)
|
||||
local c = {}
|
||||
setmetatable(c,self)
|
||||
c.max = n or math.huge
|
||||
c.stack = {}
|
||||
return c
|
||||
end
|
||||
function Stack:push(n)
|
||||
table.insert(self.stack,n)
|
||||
end
|
||||
function Stack:pop()
|
||||
return table.remove(self.stack,#self.stack)
|
||||
end
|
||||
function Stack:peek(n)
|
||||
return self.stack[#self.stack - (n or 0)]
|
||||
end
|
||||
function Stack:count()
|
||||
return #self.stack
|
||||
end
|
||||
return Stack
|
||||
100
dms/utils.lua
Normal file
100
dms/utils.lua
Normal file
@ -0,0 +1,100 @@
|
||||
-- Utils modify the global enviroment
|
||||
function string.tabs(str)
|
||||
local c = 0
|
||||
for i in str:gmatch(".") do
|
||||
if i=="\t" then
|
||||
c=c+1
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
return c
|
||||
end
|
||||
function string.trim(self)
|
||||
return (self:gsub("^%s*(.-)%s*$", "%1"))
|
||||
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)
|
||||
elseif type(v) == 'boolean' then
|
||||
print(formatting .. tostring(v))
|
||||
else
|
||||
print(formatting .. v)
|
||||
end
|
||||
end
|
||||
end
|
||||
function string.split(s,pat)
|
||||
local pat=pat or ","
|
||||
local res = {}
|
||||
local start = 1
|
||||
local state = 0
|
||||
local c = '.'
|
||||
local elem = ''
|
||||
local function helper()
|
||||
if tonumber(elem) then
|
||||
elem = tonumber(elem)
|
||||
elseif elem:sub(1,1) == "\"" and elem:sub(-1,-1) == "\"" then
|
||||
elem = elem:sub(2,-2)
|
||||
elseif elem == "true" then
|
||||
elem = true
|
||||
elseif elem == "false" then
|
||||
elem = false
|
||||
elseif elem:sub(1,1) == "{" and elem:sub(-1,-1)=="}" then
|
||||
elem = elem:sub(2,-2):split()
|
||||
else
|
||||
elem = "\1"..elem
|
||||
end
|
||||
end
|
||||
for i = 1, #s do
|
||||
c = s:sub(i, i)
|
||||
if state == 0 or state == 3 then -- start state or space after comma
|
||||
if state == 3 and c == ' ' then
|
||||
state = 0 -- skipped the space after the comma
|
||||
else
|
||||
state = 0
|
||||
if c == '"' or c=="'" then
|
||||
state = 1
|
||||
elem = elem .. '"'
|
||||
elseif c=="{" then
|
||||
state = 1
|
||||
elem = elem .. '{'
|
||||
elseif c == pat then
|
||||
helper()
|
||||
res[#res + 1] = elem
|
||||
elem = ''
|
||||
state = 3 -- skip over the next space if present
|
||||
elseif c == "(" then
|
||||
state = 1
|
||||
elem = elem .. '('
|
||||
else
|
||||
elem = elem .. c
|
||||
end
|
||||
end
|
||||
elseif state == 1 then -- inside quotes
|
||||
if c == '"' or c=="'" then --quote detection could be done here
|
||||
state = 0
|
||||
elem = elem .. '"'
|
||||
elseif c=="}" then
|
||||
state = 0
|
||||
elem = elem .. '}'
|
||||
elseif c==")" then
|
||||
state = 0
|
||||
elem = elem .. ')'
|
||||
elseif c == '\\' then
|
||||
state = 2
|
||||
else
|
||||
elem = elem .. c
|
||||
end
|
||||
elseif state == 2 then -- after \ in string
|
||||
elem = elem .. c
|
||||
state = 1
|
||||
end
|
||||
end
|
||||
helper()
|
||||
res[#res + 1] = elem
|
||||
return res
|
||||
end
|
||||
52
test.dms
52
test.dms
@ -1,42 +1,48 @@
|
||||
ENTRY main
|
||||
ENABLE test
|
||||
DISABLE test
|
||||
LOADFILE test.dat
|
||||
VERSION 1.4.5
|
||||
USING extendedDefine
|
||||
|
||||
entry main
|
||||
enable warnings
|
||||
//enable debugging
|
||||
define
|
||||
loadfile test.dat
|
||||
define
|
||||
version 1.2
|
||||
using extendedDefine as
|
||||
|
||||
[main]
|
||||
"This works!"
|
||||
"What's up"
|
||||
|
||||
Ryan "Hello how are you doing?"
|
||||
Ryan "Hello how are you doing?" // this is a comment
|
||||
Bob "I'm good you?"
|
||||
|
||||
list = {1,2,3,true,false, {1,2,3}}
|
||||
list = {1,2,3},true,"This is a string!",false, {3,2,1}
|
||||
a = list[1]
|
||||
/*
|
||||
heheheh
|
||||
sdfsdf
|
||||
ghgfh
|
||||
kjuty
|
||||
*/
|
||||
list[1] = "Hello"
|
||||
|
||||
var1,var2 = func(1,"string", 2+5)
|
||||
func(1,"string", 2+5)
|
||||
::label::
|
||||
|
||||
//Hello im testing stuff
|
||||
choice "Pick one:"
|
||||
"first" func()
|
||||
"second" func()
|
||||
"third" func()
|
||||
|
||||
for x = 1,10
|
||||
group1A
|
||||
group1B
|
||||
for y = 1,10
|
||||
group2A
|
||||
group2B
|
||||
for z = 1,10
|
||||
group3A
|
||||
group3B
|
||||
"test"
|
||||
"$x$ $y$ $z$"
|
||||
|
||||
test = true
|
||||
test2 = false
|
||||
|
||||
while cond
|
||||
...
|
||||
|
||||
if cond
|
||||
...
|
||||
elseif cond
|
||||
@ -44,7 +50,13 @@ USING extendedDefine
|
||||
else
|
||||
...
|
||||
|
||||
var1,var2 = func(1,"string", 2+5)
|
||||
func(1,"string", 2+5)
|
||||
[Ryan:char]
|
||||
age = 24
|
||||
money = 100
|
||||
|
||||
|
||||
[test:env]
|
||||
|
||||
[newblock:function()]
|
||||
"Test #2"
|
||||
"Does it parse this part properly?"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user