author | Francesco Abbate <francesco.bbt@gmail.com> | 2013年05月10日 18:07:56 +0200 |
---|---|---|
committer | Francesco Abbate <francesco.bbt@gmail.com> | 2013年05月10日 18:07:56 +0200 |
commit | 204fa404431f9c619f0dfc5ae3efc463749fa8ed (patch) | |
tree | 825fc39707d7c7b3e734c5ffb3fd04af8f325530 /expr-parse.lua | |
parent | 58dd27ba0c1776644db561cc4d565a281e2f7b2b (diff) | |
download | gsl-shell-204fa404431f9c619f0dfc5ae3efc463749fa8ed.tar.gz |
-rw-r--r-- | expr-parse.lua | 150 |
diff --git a/expr-parse.lua b/expr-parse.lua new file mode 100644 index 00000000..20129478 --- /dev/null +++ b/expr-parse.lua @@ -0,0 +1,150 @@ +local expr_lexer = require 'expr-lexer' + +local function accept(lexer, token_type) + if lexer.token.type == token_type then + lexer:next() + return true + end + return false +end + +local function expect(lexer, token_type) + if not accept(lexer, token_type) then + lexer:local_error("expecting " .. token_type) + end +end + +local expr + +local function factor(lexer, actions) + local token = lexer.token + if token.type == 'ident' then + local id = token.value + lexer:next() + if accept(lexer, '(') then + local arg = expr(lexer, actions, 0) + expect(lexer, ')') + return actions.func_eval(id, arg) + else + return actions.ident(id) + end + elseif token.type == 'number' then + local x = token.value + lexer:next() + return actions.number(x) + elseif token.type == '(' then + lexer:next() + local a = expr(lexer, actions, 0) + expect(lexer, ')') + return a + elseif token.type == 'operator' and token.symbol == '%' then + lexer:next() + if lexer.token.type ~= 'ident' then + lexer:local_error("expecting identifier:") + end + local id = lexer.token.value + lexer:next() + return actions.enum(id) + end + lexer:local_error('unexpected symbol:') +end + +local function ident_singleton(lexer, actions) + local token = lexer.token + if token.type == 'ident' then + local id = token.value + lexer:next() + if accept(lexer, '(') then + lexer:local_error('expecting simple identifier') + end + return actions.ident(id) + else + lexer:local_error('expecting simple identifier') + end +end + +local max_oper_prio = expr_lexer.max_oper_prio + +expr = function(lexer, actions, prio) + if prio > max_oper_prio then + return factor(lexer, actions) + end + + local a + local token = lexer.token + if prio == 0 and token.type == 'operator' and token.symbol == '-' then + local symbol = token.symbol + lexer:next() + local b = expr(lexer, actions, prio + 1) + a = actions.prefix(symbol, b) + else + a = expr(lexer, actions, prio + 1) + end + + token = lexer.token + while token.type == 'operator' and token.priority >= prio do + local symbol = token.symbol + accept(lexer, 'operator') + local b = expr(lexer, actions, prio + 1) + a, token = actions.infix(symbol, a, b), lexer.token + end + return a +end + +local function expr_list(lexer, actions) + local a = expr(lexer, actions, 0) + local els = actions.exprlist(a) + while accept(lexer, ',') do + local b = expr(lexer, actions, 0) + els = actions.exprlist(b, els) + end + return els +end + +local function ident_list(lexer, actions) + local a = ident_singleton(lexer, actions) + local els = actions.exprlist(a) + while accept(lexer, ',') do + local b = ident_singleton(lexer, actions) + els = actions.exprlist(b, els) + end + return els +end + +local function enums(lexer, actions) + if accept(lexer, '|') then + return ident_list(lexer, actions) + end + return {} +end + +local function conditions(lexer, actions) + if accept(lexer, ':') then + return expr_list(lexer, actions) + end + return {} +end + +local function schema(lexer, actions, accept_enums) + local y = expr(lexer, actions, 0) + expect(lexer, '~') + local x = expr_list(lexer, actions) + local enums = accept_enums and enums(lexer, actions) + local conds = conditions(lexer, actions) + expect(lexer, 'EOF') + return actions.schema(x, y, conds, enums) +end + +local expr_parse = {} + +function expr_parse.schema(formula, actions, accept_enums) + local l = expr_lexer.new(formula) + return schema(l, actions, accept_enums) +end + +function expr_parse.expr(formula, actions) + local l = expr_lexer.new(formula) + return expr(l, actions, 0) +end + +return expr_parse |