Skip to content

Instantly share code, notes, and snippets.

@cloudwu
Created July 7, 2017 01:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cloudwu/e879a8c99eed8fa03c0fd02e33880443 to your computer and use it in GitHub Desktop.
Save cloudwu/e879a8c99eed8fa03c0fd02e33880443 to your computer and use it in GitHub Desktop.
paradox file parser
local pdx = {}
do
local lpeg = require "lpeg"
local P = lpeg.P
local S = lpeg.S
local R = lpeg.R
local C = lpeg.C
local Ct = lpeg.Ct
local Cg = lpeg.Cg
local Cc = lpeg.Cc
local V = lpeg.V
local function count_lines(_,pos, parser_state)
if parser_state.pos < pos then
parser_state.line = parser_state.line + 1
parser_state.pos = pos
end
return pos
end
local exception = lpeg.Cmt( lpeg.Carg(1) , function ( _ , pos, parser_state)
error(string.format("syntax error at [%s] line (%d)", parser_state.file or "", parser_state.line))
return pos
end)
local pattern = {}
pattern.eof = P(-1)
-- blanks
do
local newline = lpeg.Cmt((P"\n" + "\r\n") * lpeg.Carg(1) ,count_lines)
local line_comment = "#" * (1 - newline) ^0 * (newline + pattern.eof)
local blank = S" \t" + newline + line_comment
pattern.blank0 = blank ^ 0
pattern.blanks = blank ^ 1
end
--number
do
local num = P "-" ^ 0 * R"09" * P "." ^ 0 * R"09" ^ 0
local percent = num / function(v) return tonumber(v) / 100 end * "%"
local number = percent + num / tonumber
local alpha = R"az" + R"AZ" + "_"
local alnum = alpha + R"09"
local word = alpha * alnum ^ 0
local const = P "@" * C(word) * pattern.blank0 * "=" * pattern.blank0 * number
pattern.word = word
pattern.const_define = lpeg.Cmt(const * lpeg.Carg(1),
function(_, pos, key, value, state)
if state.const[key] then
error (string.format("Const %s is redefined, at [%s] line (%d)", key, state.file or "", state.line))
end
state.const[key] = value
return true
end
)
local const_reference = lpeg.Cmt(P "@" * C(word) * lpeg.Carg(1),
function(_, pos, key, state)
local v = state.const[key]
if v == nil then
error (string.format("Const %s is undefined, at [%s] line (%d)", key, state.file or "", state.line))
end
return true, v
end
)
pattern.number = number + const_reference
local dotname = ("." * alnum ^ 0) ^ 0
pattern.ident = C(alpha * alnum ^ 0 * dotname)
end
pattern.key = C(pattern.word + R "09" ^ 1 / tonumber) * pattern.blank0 * "=" * pattern.blank0
local function item(t, pat)
return Cc(t) * pattern.key * pat
end
local function multipat(pat)
return Ct((pat * pattern.blanks) ^ 0 * pat^0)
end
do
local str_c = (1 - S("\\\"")) + P("\\") * 1
pattern.string = P '"' * C(str_c^0) * '"'
end
local function multi(pat)
return (Ct(pat) * pattern.blanks) ^ 0 * Ct(pat) ^ 0
end
local items = P {
"ALL",
NUMBER = item("number", pattern.number),
TABLE = item("table", P "{" * pattern.blank0 * Ct(V "ALL") * pattern.blank0 * "}" ),
ARRAY = item("array", P "{" * pattern.blank0 * Ct(V "VALUES") * pattern.blank0 * "}" ),
STRING = item("string", pattern.string),
IDENT = item("ident", pattern.ident),
CONDITION = Cc "cond" * C(pattern.word) * pattern.blank0 * C(S "<>") * pattern.blank0 * pattern.number,
DEFINE = pattern.const_define,
ITEM = V "NUMBER" + V "TABLE" + V "ARRAY" + V "STRING" + V "IDENT" + V "CONDITION" + V "DEFINE",
VALUE = C(pattern.number) + C(pattern.string),
VALUES = multi(V "VALUE"),
ALL = multi(V "ITEM"),
}
local proto = pattern.blank0 * Ct(items)
function pdx.parser(text,filename)
local state = { file = filename, pos = 0, line = 1 , const = {}}
local r = lpeg.match(proto * -1 + exception , text , 1, state )
return r
end
end
function pdx.load(filename)
local f = assert(io.open(filename))
local text = f:read "a"
f:close()
local tmp = pdx.parser(text, filename)
return tmp
end
return pdx
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment