################################################################################ # Copyright (c) 2011-2014, Tenable Network Security # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ################################################################################ class Nasl::Grammar preclow right ASS_EQ ADD_EQ SUB_EQ MUL_EQ DIV_EQ MOD_EQ SLL_EQ SRA_EQ SRL_EQ left OR left AND left CMP_LT CMP_GT CMP_EQ CMP_NE CMP_GE CMP_LE SUBSTR_EQ SUBSTR_NE REGEX_EQ REGEX_NE left BIT_OR left BIT_XOR left AMPERSAND left BIT_SRA BIT_SRL BIT_SLL left ADD SUB left MUL DIV MOD right NOT right UMINUS BIT_NOT right EXP right INCR DECR prechigh # Tell the parser generator that we don't wish to use the result variable in the # action section of rules. Instead, the result of the rule will be the value of # evaluating the action block. options no_result_var # Tell the parser generator that we expect one shift/reduce conflict due to the # well-known dangling else problem. We could make the grammar solve this # problem, but this is how the NASL YACC file solves it, so we'll follow suit. expect 1 rule ############################################################################## # Aggregate Statements ############################################################################## start : roots { val[0] } | /* Blank */ { [] } ; roots : root roots { [val[0]] + val[1] } | root { [val[0]] } ; root : COMMENT export { c(*val) } | export { val[0] } | COMMENT function { c(*val) } | function { val[0] } | statement { val[0] } ; statement : simple { val[0] } | compound { val[0] } ; ############################################################################## # Root Statements ############################################################################## export : EXPORT function { n(:Export, *val) } ; function : FUNCTION ident LPAREN params RPAREN block { n(:Function, *val) } | FUNCTION ident LPAREN RPAREN block { n(:Function, *val) } ; simple : assign { val[0] } | break { val[0] } | call { val[0] } | continue { val[0] } | decr { val[0] } | empty { val[0] } | COMMENT global { c(*val) } | global { val[0] } | import { val[0] } | include { val[0] } | incr { val[0] } | local { val[0] } | rep { val[0] } | return { val[0] } ; compound : block { val[0] } | for { val[0] } | foreach { val[0] } | if { val[0] } | repeat { val[0] } | while { val[0] } ; ############################################################################## # Simple Statements ############################################################################## assign : assign_exp SEMICOLON { val[0] } ; break : BREAK SEMICOLON { n(:Break, *val) } ; call : call_exp SEMICOLON { val[0] } ; continue : CONTINUE SEMICOLON { n(:Continue, *val) } ; decr : decr_exp SEMICOLON { val[0] } ; empty : SEMICOLON { n(:Empty, *val) } ; global : GLOBAL var_decls SEMICOLON { n(:Global, *val) } ; incr : incr_exp SEMICOLON { val[0] } ; import : IMPORT LPAREN string RPAREN SEMICOLON { n(:Import, *val) } ; include : INCLUDE LPAREN string RPAREN SEMICOLON { n(:Include, *val) } ; local : LOCAL var_decls SEMICOLON { n(:Local, *val) } ; rep : call_exp REP expr SEMICOLON { n(:Repetition, *val[0..-1]) } ; return : RETURN expr SEMICOLON { n(:Return, *val) } | RETURN ref SEMICOLON { n(:Return, *val) } | RETURN SEMICOLON { n(:Return, *val) } ; ############################################################################## # Compound Statements ############################################################################## block : LBRACE statements RBRACE { n(:Block, *val) } | LBRACE RBRACE { n(:Block, *val) } ; for : FOR LPAREN field SEMICOLON expr SEMICOLON field RPAREN statement { n(:For, *val) } ; foreach : FOREACH ident LPAREN expr RPAREN statement { n(:Foreach, val[0], val[1], val[3], val[5]) } | FOREACH LPAREN ident IN expr RPAREN statement { n(:Foreach, val[0], val[2], val[4], val[6]) } ; if : IF LPAREN expr RPAREN statement { n(:If, *val) } | IF LPAREN expr RPAREN statement ELSE statement { n(:If, *val) } ; repeat : REPEAT statement UNTIL expr SEMICOLON { n(:Repeat, *val) } ; while : WHILE LPAREN expr RPAREN statement { n(:While, *val) } ; ############################################################################## # Expressions ############################################################################## assign_exp : lval ASS_EQ expr { n(:Assignment, *val) } | lval ASS_EQ ref { n(:Assignment, *val) } | lval ADD_EQ expr { n(:Assignment, *val) } | lval SUB_EQ expr { n(:Assignment, *val) } | lval MUL_EQ expr { n(:Assignment, *val) } | lval DIV_EQ expr { n(:Assignment, *val) } | lval MOD_EQ expr { n(:Assignment, *val) } | lval SRL_EQ expr { n(:Assignment, *val) } | lval SRA_EQ expr { n(:Assignment, *val) } | lval SLL_EQ expr { n(:Assignment, *val) } ; call_exp : lval LPAREN args RPAREN { n(:Call, *val) } | lval LPAREN RPAREN { n(:Call, *val) } ; decr_exp : DECR lval { n(:Decrement, val[0]) } | lval DECR { n(:Decrement, val[0]) } ; incr_exp : INCR lval { n(:Increment, val[0]) } | lval INCR { n(:Increment, val[0]) } ; expr : LPAREN expr RPAREN { n(:Expression, *val) } | expr AND expr { n(:Expression, *val) } | NOT expr { n(:Expression, *val) } | expr OR expr { n(:Expression, *val) } | expr ADD expr { n(:Expression, *val) } | expr SUB expr { n(:Expression, *val) } | SUB expr =UMINUS { n(:Expression, *val) } | BIT_NOT expr { n(:Expression, *val) } | expr MUL expr { n(:Expression, *val) } | expr EXP expr { n(:Expression, *val) } | expr DIV expr { n(:Expression, *val) } | expr MOD expr { n(:Expression, *val) } | expr AMPERSAND expr { n(:Expression, *val) } | expr BIT_XOR expr { n(:Expression, *val) } | expr BIT_OR expr { n(:Expression, *val) } | expr BIT_SRA expr { n(:Expression, *val) } | expr BIT_SRL expr { n(:Expression, *val) } | expr BIT_SLL expr { n(:Expression, *val) } | incr_exp { val[0] } | decr_exp { val[0] } | expr SUBSTR_EQ expr { n(:Expression, *val) } | expr SUBSTR_NE expr { n(:Expression, *val) } | expr REGEX_EQ expr { n(:Expression, *val) } | expr REGEX_NE expr { n(:Expression, *val) } | expr CMP_LT expr { n(:Expression, *val) } | expr CMP_GT expr { n(:Expression, *val) } | expr CMP_EQ expr { n(:Expression, *val) } | expr CMP_NE expr { n(:Expression, *val) } | expr CMP_GE expr { n(:Expression, *val) } | expr CMP_LE expr { n(:Expression, *val) } | assign_exp { val[0] } | string { val[0] } | call_exp { val[0] } | lval { val[0] } | ip { val[0] } | int { val[0] } | undef { val[0] } | list_expr { val[0] } | array_expr { val[0] } ; ############################################################################## # Named Components ############################################################################## arg : ident COLON expr { n(:Argument, *val) } | ident COLON ref { n(:Argument, *val) } | expr { n(:Argument, *val) } | ref { n(:Argument, *val) } ; kv_pair : string COLON expr { n(:KeyValuePair, *val) } | int COLON expr { n(:KeyValuePair, *val) } | ident COLON expr { n(:KeyValuePair, *val) } | string COLON ref { n(:KeyValuePair, *val) } | int COLON ref { n(:KeyValuePair, *val) } | ident COLON ref { n(:KeyValuePair, *val) } ; kv_pairs : kv_pair COMMA kv_pairs { [val[0]] + val[2] } | kv_pair COMMA { [val[0]] } | kv_pair { [val[0]] } ; lval : ident indexes { n(:Lvalue, *val) } | ident { n(:Lvalue, *val) } ; ref : AT_SIGN ident { n(:Reference, val[1]) } ; ############################################################################## # Anonymous Components ############################################################################## args : arg COMMA args { [val[0]] + val[2] } | arg { [val[0]] } ; array_expr : LBRACE kv_pairs RBRACE { n(:Array, *val) } | LBRACE RBRACE { n(:Array, *val) } ; field : assign_exp { val[0] } | call_exp { val[0] } | decr_exp { val[0] } | incr_exp { val[0] } | /* Blank */ { nil } ; index : LBRACK expr RBRACK { val[1] } | PERIOD ident { val[1] } ; indexes : index indexes { [val[0]] + val[1] } | index { [val[0]] } ; list_elem : expr { val[0] } | ref { val[0] } ; list_elems : list_elem COMMA list_elems { [val[0]] + val[2] } | list_elem { [val[0]] } ; list_expr : LBRACK list_elems RBRACK { n(:List, *val) } | LBRACK RBRACK { n(:List, *val) } ; param : AMPERSAND ident { n(:Parameter, val[1], 'reference') } | ident { n(:Parameter, val[0], 'value') } ; params : param COMMA params { [val[0]] + val[2] } | param { [val[0]] } ; statements : statement statements { [val[0]] + val[1] } | statement { [val[0]] } ; var_decl : ident ASS_EQ expr { n(:Assignment, *val) } | ident ASS_EQ ref { n(:Assignment, *val) } | ident { val[0] } ; var_decls : var_decl COMMA var_decls { [val[0]] + val[2] } | var_decl { [val[0]] } ; ############################################################################## # Literals ############################################################################## ident : IDENT { n(:Identifier, *val) } | REP { n(:Identifier, *val) } | IN { n(:Identifier, *val) } ; int : INT_DEC { n(:Integer, *val) } | INT_HEX { n(:Integer, *val) } | INT_OCT { n(:Integer, *val) } | FALSE { n(:Integer, *val) } | TRUE { n(:Integer, *val) } ; ip : int PERIOD int PERIOD int PERIOD int { n(:Ip, *val) } string : DATA { n(:String, *val) } | STRING { n(:String, *val) } ; undef : UNDEF { n(:Undefined, *val) } ; end ---- header ---- require 'nasl/parser/tree' require 'nasl/parser/argument' require 'nasl/parser/array' require 'nasl/parser/assigment' require 'nasl/parser/block' require 'nasl/parser/break' require 'nasl/parser/call' require 'nasl/parser/comment' require 'nasl/parser/continue' require 'nasl/parser/decrement' require 'nasl/parser/empty' require 'nasl/parser/export' require 'nasl/parser/expression' require 'nasl/parser/for' require 'nasl/parser/foreach' require 'nasl/parser/function' require 'nasl/parser/global' require 'nasl/parser/identifier' require 'nasl/parser/if' require 'nasl/parser/import' require 'nasl/parser/include' require 'nasl/parser/increment' require 'nasl/parser/integer' require 'nasl/parser/ip' require 'nasl/parser/key_value_pair' require 'nasl/parser/list' require 'nasl/parser/local' require 'nasl/parser/lvalue' require 'nasl/parser/parameter' require 'nasl/parser/reference' require 'nasl/parser/repeat' require 'nasl/parser/repetition' require 'nasl/parser/return' require 'nasl/parser/string' require 'nasl/parser/undefined' require 'nasl/parser/while' ---- inner ---- def n(cls, *args) begin Nasl.const_get(cls).new(@tree, *args) rescue puts "An exception occurred during the creation of a #{cls} instance." puts puts "The arguments passed to the constructor were:" puts args puts puts @tok.last.context puts raise end end def c(*args) n(:Comment, *args) args[1] end def on_error(type, value, stack) raise ParseException, "The language's grammar does not permit #{value.name} to appear here", value.context end def next_token @tok = @tkz.get_token if @first && @tok.first == :COMMENT n(:Comment, @tok.last) @tok = @tkz.get_token end @first = false return @tok end def parse(env, code, path) @first = true @tree = Tree.new(env) @tkz = Tokenizer.new(code, path) @tree.concat(do_parse) end ---- footer ----