Created
April 27, 2014 13:55
-
-
Save AndrewTsao/11346217 to your computer and use it in GitHub Desktop.
learning lpeg module to write a mini expression executor.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- | |
-- 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