From 51f6da113754ea960f362f24620ffe6c68b3417b Mon Sep 17 00:00:00 2001 From: Diego Pino Garcia <dpino@igalia.com> Date: Thu, 14 Aug 2014 19:46:36 +0200 Subject: [PATCH] Implement implicit "OR". If an identifier is given without a keyword, the most recent keyword is assumed. For example, not host vs and ace is short for not host vs and host ace Which should not be confused with not ( host vs or ace ) This patch fixes issue #17. --- src/pf/parse.lua | 53 +++++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/src/pf/parse.lua b/src/pf/parse.lua index 1c47ce0..d7e4dba 100644 --- a/src/pf/parse.lua +++ b/src/pf/parse.lua @@ -233,26 +233,15 @@ local function tokens(str) local tok = next(opts) assert(tok == expected, "expected "..expected..", got: "..tok) end + local function put(tok) + str = string.sub(str, 1, pos - 1)..tok..string.sub(str, pos + 1) + end local function check(expected, opts) if peek(opts) ~= expected then return false end next() return true end - local function error_str(message, ...) - local location_error_message = "Error: In expression \"%s\"" - local start = #location_error_message - 4 - local cursor_pos = start + last_pos - - local result = "\n" - result = result..location_error_message:format(str).."\n" - result = result..string.rep(" ", cursor_pos).."^".."\n" - result = result..message:format(...).."\n" - return result - end - local function error(message, ...) - primitive_error(error_str(message, ...)) - end - return { peek = peek, next = next, consume = consume, check = check, error = error } + return { peek = peek, next = next, consume = consume, check = check, put = put } end local addressables = set( @@ -685,6 +674,16 @@ function parse_arithmetic(lexer, tok, max_precedence, parsed_exp) end end +local last_keyword = (function() + local keyword = nil + return function(arg) + if arg ~= nil then + keyword = arg + end + return keyword + end +end)() + local function parse_primitive_or_arithmetic(lexer) local tok = lexer.next({maybe_arithmetic=true}) if (type(tok) == 'number' or tok == 'len' or @@ -693,15 +692,18 @@ local function parse_primitive_or_arithmetic(lexer) end local parser = primitives[tok] - if parser then return parser(lexer, tok) end + if parser then + last_keyword(tok) + return parser(lexer, tok) + else + lexer.put(tok) + local parser = primitives[last_keyword()] + if parser then + return parser(lexer, last_keyword()) + end + end - -- At this point the official pcap grammar is squirrely. It says: - -- "If an identifier is given without a keyword, the most recent - -- keyword is assumed. For example, `not host vs and ace' is - -- short for `not host vs and host ace` and which should not be - -- confused with `not (host vs or ace)`." For now we punt on this - -- part of the grammar. - lexer.error('keyword elision not implemented %s', tok) + lexer.error(string.format("keyword elision not implemented: %s", tok)) end local logical_precedence = { @@ -769,6 +771,7 @@ function parse(str) if not lexer.peek({maybe_arithmetic=true}) then return { 'true' } end local expr = parse_logical(lexer) assert(not lexer.peek(), "unexpected token", lexer.peek()) + last_keyword("") return expr end @@ -858,5 +861,9 @@ function selftest () { 'ether_host', { 'ehost', 255, 255, 255, 51, 51, 51 } }) parse_test("ether host f:f:f:3:3:3", { 'ether_host', { 'ehost', 240, 240, 240, 48, 48, 48 } }) + parse_test("not host vs and ace", + { 'not', { 'and', { 'host', 'vs' }, { 'host', 'ace' } } } ) + parse_test("not ( host vs or ace )", + { 'not', { 'or', { 'host', 'vs' }, { 'host', 'ace' } } } ) print("OK") end