Skip to content

Instantly share code, notes, and snippets.

@AndrewTsao
Created April 27, 2014 13:55
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 AndrewTsao/11346217 to your computer and use it in GitHub Desktop.
Save AndrewTsao/11346217 to your computer and use it in GitHub Desktop.
learning lpeg module to write a mini expression executor.
--
-- Created by IntelliJ IDEA.
-- User: andi
-- Date: 14-4-27
-- Time: 下午7:07
-- To change this template use File | Settings | File Templates.
--
local sqrt = require("math").sqrt
local re = require("re")
local function printIndent(v, n)
n = n or 0
print(string.rep(" ", n)..v);
end
local function p(t, indent)
indent = indent or 0
if indent > 5 then return end
if not t then
printIndent('<nil>', indent)
return
end
if type(t) == 'table' then
printIndent("{", indent)
for k, v in pairs(t) do
if type(v) == 'table' then
printIndent(k .. ":", indent + 1)
p(v, indent + 1)
else
printIndent(k .. ":" .. v, indent + 1)
end
end
printIndent("}", indent)
else
printIndent(t, indent)
end
end
local grammer = [[
stmt <- <expr> (%nl/!.)
expr <- (s (<term>) {| (s (<termOp>) s (<term>) s)* |}) -> doTerm
termOp <- (('+' / '-')) -> Op
term <- (s (<factor>) {| (s (<factorOp>) s (<factor>) s)* |}) -> doFactor
factorOp <- (('*' / '/')) -> Op
factor <- <num> / '(' <expr> ')' / <func> -> doNum
func <- (<id> '(' <args> ')') -> doFunc
id <- {[A-Za-z_][A-Za-z0-9_]*} -> doId
args <- ((<expr>) {| (',' (<expr>))* |}) -> doArgs
num <- {[0-9]+} -> tonumber
s <- %s*
]]
local defs = {
tonumber = tonumber,
doTerm = function(left, rights)
local ret = left
if not rights then
return ret
end
for i = 1, #rights, 2 do
local operator = rights[i]
local right = rights[i + 1]
ret = operator == '+' and (ret + right) or (ret - right)
end
return ret
end,
Op = function(operator)
return operator
end,
doFactor = function(left, rights)
local ret = left
if not rights then
return ret
end
for i = 1, #rights, 2 do
local operator = rights[i]
local right = rights[i + 1]
ret = operator == '*' and (ret * right) or (ret / right)
end
return ret
end,
doFunc = function(id, args)
return id(args)
end,
doId = function(name)
if name == 'sqrt' then
return sqrt
end
error("invalid functiion name")
end,
doArgs = function(args)
return args
end,
doNum = function(num)
return num
end,
}
local matcher = re.compile(grammer, defs)
p(matcher:match('1+2'))
p(matcher:match('1*3'))
p(matcher:match('1+1+2'))
p(matcher:match('1+4/1*4+2*2-sqrt(16)'))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment