зеркало из https://github.com/github/ruby.git
627 строки
17 KiB
Plaintext
627 строки
17 KiB
Plaintext
################################################################################
|
|
# 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 ----
|