Parser can parse more commands

This commit is contained in:
Ryan Ward 2020-05-31 01:30:03 -04:00
parent bee1d90bf1
commit a6a16e614a
9 changed files with 608 additions and 157 deletions

64
DMS.xml Normal file
View 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">+ - * / = ( ) [ ] , &gt; &lt; ~ ! | ; :</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&quot; 07 08&quot; 09 10 11 12&apos; 13 14&apos; 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>

View File

@ -1,137 +1,4 @@
file = io.open("test.dms","rb") package.path="?.lua;?/init.lua;?.lua;?/?/init.lua;"..package.path
content = file:read("*a") local parser = require("dms.parser")
line_num = 0 local p = parser:new("test.dms")
CMD = {} p:parse()
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

33
dms/chunk.lua Normal file
View 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
View 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
View File

335
dms/parser.lua Normal file
View 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
View 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
View 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

View File

@ -1,42 +1,48 @@
ENTRY main entry main
ENABLE test enable warnings
DISABLE test //enable debugging
LOADFILE test.dat define
VERSION 1.4.5 loadfile test.dat
USING extendedDefine define
version 1.2
using extendedDefine as
[main] [main]
"This works!" "This works!"
"What's up" "What's up"
Ryan "Hello how are you doing?" Ryan "Hello how are you doing?" // this is a comment
Bob "I'm good you?" 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] a = list[1]
/*
heheheh
sdfsdf
ghgfh
kjuty
*/
list[1] = "Hello" list[1] = "Hello"
var1,var2 = func(1,"string", 2+5)
func(1,"string", 2+5)
::label:: ::label::
//Hello im testing stuff
choice "Pick one:" choice "Pick one:"
"first" func() "first" func()
"second" func() "second" func()
"third" func() "third" func()
for x = 1,10 for x = 1,10
group1A
group1B
for y = 1,10 for y = 1,10
group2A
group2B
for z = 1,10 for z = 1,10
group3A "test"
group3B "$x$ $y$ $z$"
test = true
test2 = false
while cond while cond
... ...
if cond if cond
... ...
elseif cond elseif cond
@ -44,7 +50,13 @@ USING extendedDefine
else else
... ...
var1,var2 = func(1,"string", 2+5) [Ryan:char]
func(1,"string", 2+5) age = 24
money = 100
[test:env]
[newblock:function()] [newblock:function()]
"Test #2"
"Does it parse this part properly?"