nasl 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +9 -0
- data/Gemfile +4 -0
- data/Rakefile +8 -0
- data/bin/nasl-parse +33 -0
- data/lib/nasl/cli.rb +94 -0
- data/lib/nasl/command.rb +96 -0
- data/lib/nasl/commands/benchmark.rb +55 -0
- data/lib/nasl/commands/parse.rb +55 -0
- data/lib/nasl/commands/test.rb +37 -0
- data/lib/nasl/commands/tokenize.rb +46 -0
- data/lib/nasl/commands/xml.rb +41 -0
- data/lib/nasl/context.rb +102 -0
- data/lib/nasl/grammar.racc +513 -0
- data/lib/nasl/grammar.tab.rb +1650 -0
- data/lib/nasl/parser/argument.rb +50 -0
- data/lib/nasl/parser/assigment.rb +45 -0
- data/lib/nasl/parser/block.rb +41 -0
- data/lib/nasl/parser/break.rb +32 -0
- data/lib/nasl/parser/call.rb +48 -0
- data/lib/nasl/parser/continue.rb +32 -0
- data/lib/nasl/parser/decrement.rb +48 -0
- data/lib/nasl/parser/empty.rb +32 -0
- data/lib/nasl/parser/export.rb +41 -0
- data/lib/nasl/parser/expression.rb +56 -0
- data/lib/nasl/parser/for.rb +47 -0
- data/lib/nasl/parser/foreach.rb +45 -0
- data/lib/nasl/parser/function.rb +45 -0
- data/lib/nasl/parser/global.rb +41 -0
- data/lib/nasl/parser/identifier.rb +43 -0
- data/lib/nasl/parser/if.rb +45 -0
- data/lib/nasl/parser/import.rb +41 -0
- data/lib/nasl/parser/include.rb +41 -0
- data/lib/nasl/parser/increment.rb +48 -0
- data/lib/nasl/parser/integer.rb +70 -0
- data/lib/nasl/parser/ip.rb +43 -0
- data/lib/nasl/parser/local.rb +41 -0
- data/lib/nasl/parser/lvalue.rb +43 -0
- data/lib/nasl/parser/node.rb +73 -0
- data/lib/nasl/parser/repeat.rb +43 -0
- data/lib/nasl/parser/repetition.rb +43 -0
- data/lib/nasl/parser/return.rb +41 -0
- data/lib/nasl/parser/string.rb +48 -0
- data/lib/nasl/parser/tree.rb +59 -0
- data/lib/nasl/parser/undefined.rb +35 -0
- data/lib/nasl/parser/while.rb +43 -0
- data/lib/nasl/parser.rb +45 -0
- data/lib/nasl/test.rb +98 -0
- data/lib/nasl/token.rb +69 -0
- data/lib/nasl/tokenizer.rb +327 -0
- data/lib/nasl/version.rb +3 -0
- data/lib/nasl.rb +52 -0
- data/nasl.gemspec +26 -0
- data/test/test_helper.rb +6 -0
- data/test/unit/parser/test_assignment.rb +111 -0
- data/test/unit/parser/test_blank.rb +44 -0
- data/test/unit/parser/test_block.rb +35 -0
- data/test/unit/parser/test_constant.rb +65 -0
- data/test/unit/parser/test_empty.rb +36 -0
- data/test/unit/parser/test_expressions.rb +57 -0
- data/test/unit/parser/test_function.rb +82 -0
- data/test/unit/parser/test_if.rb +85 -0
- data/test/unit/parser/test_include.rb +37 -0
- data/test/unit/parser/test_incr_decr.rb +51 -0
- data/test/unit/parser/test_ip.rb +33 -0
- data/test/unit/parser/test_return.rb +51 -0
- data/test/unit/parser/test_string.rb +46 -0
- data/test/unit/parser/test_whitespace.rb +56 -0
- data/test/unit/test_context.rb +240 -0
- data/test/unit/tokenizer/test_empty.rb +53 -0
- data/test/unit/tokenizer/test_integer.rb +68 -0
- data/test/unit/tokenizer/test_string.rb +94 -0
- metadata +161 -0
@@ -0,0 +1,59 @@
|
|
1
|
+
################################################################################
|
2
|
+
# Copyright (c) 2011, Mak Kolybabi
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without
|
6
|
+
# modification, are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# 1. Redistributions of source code must retain the above copyright notice, this
|
9
|
+
# list of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
12
|
+
# this list of conditions and the following disclaimer in the documentation
|
13
|
+
# and/or other materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
16
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
17
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
18
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
19
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
20
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
21
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
22
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
23
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
24
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
25
|
+
################################################################################
|
26
|
+
|
27
|
+
require 'builder'
|
28
|
+
|
29
|
+
module Nasl
|
30
|
+
class Tree < Array
|
31
|
+
def all(cls)
|
32
|
+
(@all[Nasl.const_get(cls).to_s] ||= [])
|
33
|
+
end
|
34
|
+
|
35
|
+
def register(node)
|
36
|
+
(@all[node.class.name] ||= []) << node
|
37
|
+
@parent.register(node) unless @parent.nil?
|
38
|
+
end
|
39
|
+
|
40
|
+
def initialize(parent=nil)
|
41
|
+
@parent = parent
|
42
|
+
@all = {}
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_s
|
46
|
+
text = ''
|
47
|
+
|
48
|
+
xml = Builder::XmlMarkup.new(:target=>text, :indent=>2)
|
49
|
+
|
50
|
+
if empty?
|
51
|
+
xml.tree
|
52
|
+
else
|
53
|
+
xml.tree { self.map { |node| node.to_xml(xml) } }
|
54
|
+
end
|
55
|
+
|
56
|
+
text
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
################################################################################
|
2
|
+
# Copyright (c) 2011, Mak Kolybabi
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without
|
6
|
+
# modification, are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# 1. Redistributions of source code must retain the above copyright notice, this
|
9
|
+
# list of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
12
|
+
# this list of conditions and the following disclaimer in the documentation
|
13
|
+
# and/or other materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
16
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
17
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
18
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
19
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
20
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
21
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
22
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
23
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
24
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
25
|
+
################################################################################
|
26
|
+
|
27
|
+
require 'nasl/parser/node'
|
28
|
+
|
29
|
+
module Nasl
|
30
|
+
class Undefined < Node
|
31
|
+
def to_xml(xml)
|
32
|
+
xml.null
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
################################################################################
|
2
|
+
# Copyright (c) 2011, Mak Kolybabi
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without
|
6
|
+
# modification, are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# 1. Redistributions of source code must retain the above copyright notice, this
|
9
|
+
# list of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
12
|
+
# this list of conditions and the following disclaimer in the documentation
|
13
|
+
# and/or other materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
16
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
17
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
18
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
19
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
20
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
21
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
22
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
23
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
24
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
25
|
+
################################################################################
|
26
|
+
|
27
|
+
require 'nasl/parser/node'
|
28
|
+
|
29
|
+
module Nasl
|
30
|
+
class While < Node
|
31
|
+
attr_reader :body, :cond
|
32
|
+
|
33
|
+
def initialize(tree, *tokens)
|
34
|
+
super
|
35
|
+
|
36
|
+
@cond = @tokens[2]
|
37
|
+
@body = @tokens[4]
|
38
|
+
|
39
|
+
@attributes << :cond
|
40
|
+
@attributes << :body
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/nasl/parser.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
################################################################################
|
2
|
+
# Copyright (c) 2011, Mak Kolybabi
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without
|
6
|
+
# modification, are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# 1. Redistributions of source code must retain the above copyright notice, this
|
9
|
+
# list of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
12
|
+
# this list of conditions and the following disclaimer in the documentation
|
13
|
+
# and/or other materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
16
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
17
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
18
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
19
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
20
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
21
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
22
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
23
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
24
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
25
|
+
################################################################################
|
26
|
+
|
27
|
+
require 'racc/parser'
|
28
|
+
require 'nasl/grammar.tab'
|
29
|
+
require 'nasl/parser/tree'
|
30
|
+
|
31
|
+
module Nasl
|
32
|
+
class ParseException < Exception
|
33
|
+
end
|
34
|
+
|
35
|
+
class Parser
|
36
|
+
def initialize
|
37
|
+
@grammar = Grammar.new
|
38
|
+
@env = Tree.new
|
39
|
+
end
|
40
|
+
|
41
|
+
def parse(code, path="(unknown)")
|
42
|
+
@grammar.parse(@env, code, path)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/nasl/test.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
################################################################################
|
2
|
+
# Copyright (c) 2011, Mak Kolybabi
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without
|
6
|
+
# modification, are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# 1. Redistributions of source code must retain the above copyright notice, this
|
9
|
+
# list of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
12
|
+
# this list of conditions and the following disclaimer in the documentation
|
13
|
+
# and/or other materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
16
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
17
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
18
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
19
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
20
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
21
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
22
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
23
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
24
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
25
|
+
################################################################################
|
26
|
+
|
27
|
+
require 'nasl/parser'
|
28
|
+
require 'test/unit'
|
29
|
+
|
30
|
+
module Nasl
|
31
|
+
module Test
|
32
|
+
def self.initialize!(args)
|
33
|
+
# Run all tests by default.
|
34
|
+
args = ['unit/*', 'unit/*/*'] if args.empty?
|
35
|
+
|
36
|
+
# Run each test or category of tests specified on the command line.
|
37
|
+
args.each do |test|
|
38
|
+
Dir.glob(Nasl.test + (test + '.rb')).each { |f| load(f) }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def flatten(tree)
|
43
|
+
tree.chomp.split(/\n/).map(&:strip).join
|
44
|
+
end
|
45
|
+
|
46
|
+
def parse(code)
|
47
|
+
begin
|
48
|
+
tree = Nasl::Parser.new.parse(code)
|
49
|
+
msg = ''
|
50
|
+
rescue Racc::ParseError => e
|
51
|
+
tree = nil
|
52
|
+
msg = e
|
53
|
+
end
|
54
|
+
|
55
|
+
return tree, msg
|
56
|
+
end
|
57
|
+
|
58
|
+
def tokenize(code)
|
59
|
+
Nasl::Tokenizer.new(code, "(test)")
|
60
|
+
end
|
61
|
+
|
62
|
+
def context(code)
|
63
|
+
Nasl::Context.new(code, "(test)")
|
64
|
+
end
|
65
|
+
|
66
|
+
def fail(code)
|
67
|
+
tree, msg = parse(code)
|
68
|
+
|
69
|
+
assert_nil(tree, msg)
|
70
|
+
end
|
71
|
+
|
72
|
+
def fail_parse(code)
|
73
|
+
assert_raise(ParseException) { Nasl::Parser.new.parse(code) }
|
74
|
+
end
|
75
|
+
|
76
|
+
def fail_token(code)
|
77
|
+
assert_raise(TokenException) { Nasl::Parser.new.parse(code) }
|
78
|
+
end
|
79
|
+
|
80
|
+
def pass(code)
|
81
|
+
tree, msg = parse(code)
|
82
|
+
|
83
|
+
assert_not_nil(tree, msg)
|
84
|
+
end
|
85
|
+
|
86
|
+
def diff(code, kg_tree)
|
87
|
+
tree, msg = parse(code)
|
88
|
+
assert_not_nil(tree, msg)
|
89
|
+
assert_not_equal(flatten(kg_tree), flatten(tree.to_s)) if !tree.nil?
|
90
|
+
end
|
91
|
+
|
92
|
+
def same(code, kg_tree)
|
93
|
+
tree, msg = parse(code)
|
94
|
+
assert_not_nil(tree, msg)
|
95
|
+
assert_equal(flatten(kg_tree), flatten(tree.to_s)) if !tree.nil?
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
data/lib/nasl/token.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
###############################################################################
|
2
|
+
# Copyright (c) 2011, Mak Kolybabi
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without
|
6
|
+
# modification, are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# 1. Redistributions of source code must retain the above copyright notice, this
|
9
|
+
# list of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
12
|
+
# this list of conditions and the following disclaimer in the documentation
|
13
|
+
# and/or other materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
16
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
17
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
18
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
19
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
20
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
21
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
22
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
23
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
24
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
25
|
+
################################################################################
|
26
|
+
|
27
|
+
module Nasl
|
28
|
+
class Token
|
29
|
+
attr_reader :body, :name, :region, :type
|
30
|
+
|
31
|
+
def initialize(type, body, region, ctx)
|
32
|
+
@type = type
|
33
|
+
@body = body
|
34
|
+
@region = region
|
35
|
+
@ctx = ctx
|
36
|
+
end
|
37
|
+
|
38
|
+
def context(*args)
|
39
|
+
@ctx.context(@region, *args)
|
40
|
+
end
|
41
|
+
|
42
|
+
def name
|
43
|
+
case @type
|
44
|
+
when *[:BREAK, :CONTINUE, :ELSE, :EXPORT, :FOR, :FOREACH, :FUNCTION,
|
45
|
+
:GLOBAL, :IF, :IMPORT, :INCLUDE, :LOCAL, :REPEAT, :RETURN, :UNTIL,
|
46
|
+
:REP, :WHILE]
|
47
|
+
"a keyword"
|
48
|
+
when :UNDEF
|
49
|
+
"an undefined constant"
|
50
|
+
when *[:FALSE, :TRUE]
|
51
|
+
"a boolean constant"
|
52
|
+
when :IDENT
|
53
|
+
"an identifier"
|
54
|
+
when *[:DATA, :STRING]
|
55
|
+
"a string"
|
56
|
+
when *[:INT_DEC, :INT_HEX, :INT_OCT]
|
57
|
+
"an integer"
|
58
|
+
when :EOF
|
59
|
+
"the end of the file"
|
60
|
+
else
|
61
|
+
"an operator"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def to_s
|
66
|
+
@body
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,327 @@
|
|
1
|
+
###############################################################################
|
2
|
+
# Copyright (c) 2011, Mak Kolybabi
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without
|
6
|
+
# modification, are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# 1. Redistributions of source code must retain the above copyright notice, this
|
9
|
+
# list of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
12
|
+
# this list of conditions and the following disclaimer in the documentation
|
13
|
+
# and/or other materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
16
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
17
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
18
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
19
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
20
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
21
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
22
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
23
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
24
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
25
|
+
################################################################################
|
26
|
+
|
27
|
+
module Nasl
|
28
|
+
class TokenException < Exception
|
29
|
+
end
|
30
|
+
|
31
|
+
class Tokenizer
|
32
|
+
@@initialized = false
|
33
|
+
|
34
|
+
@@keywords = {
|
35
|
+
'break' => :BREAK,
|
36
|
+
'continue' => :CONTINUE,
|
37
|
+
'else' => :ELSE,
|
38
|
+
'export' => :EXPORT,
|
39
|
+
'for' => :FOR,
|
40
|
+
'foreach' => :FOREACH,
|
41
|
+
'function' => :FUNCTION,
|
42
|
+
'global_var' => :GLOBAL,
|
43
|
+
'if' => :IF,
|
44
|
+
'import' => :IMPORT,
|
45
|
+
'include' => :INCLUDE,
|
46
|
+
'local_var' => :LOCAL,
|
47
|
+
'repeat' => :REPEAT,
|
48
|
+
'return' => :RETURN,
|
49
|
+
'until' => :UNTIL,
|
50
|
+
'x' => :REP,
|
51
|
+
'while' => :WHILE,
|
52
|
+
|
53
|
+
'FALSE' => :FALSE,
|
54
|
+
'NULL' => :UNDEF,
|
55
|
+
'TRUE' => :TRUE
|
56
|
+
}
|
57
|
+
|
58
|
+
@@operators = [
|
59
|
+
["><", :SUBSTR_EQ],
|
60
|
+
[">!<", :SUBSTR_NE],
|
61
|
+
|
62
|
+
["=~", :REGEX_EQ],
|
63
|
+
["!~", :REGEX_NE],
|
64
|
+
|
65
|
+
["==", :CMP_EQ],
|
66
|
+
["!=", :CMP_NE],
|
67
|
+
["<=", :CMP_LE],
|
68
|
+
[">=", :CMP_GE],
|
69
|
+
|
70
|
+
["=", :ASS_EQ],
|
71
|
+
["+=", :ADD_EQ],
|
72
|
+
["-=", :SUB_EQ],
|
73
|
+
["*=", :MUL_EQ],
|
74
|
+
["/=", :DIV_EQ],
|
75
|
+
["%=", :MOD_EQ],
|
76
|
+
[">>=", :SRL_EQ],
|
77
|
+
[">>>=", :SRA_EQ],
|
78
|
+
["<<=", :SLL_EQ],
|
79
|
+
|
80
|
+
["||", :OR],
|
81
|
+
["&&", :AND],
|
82
|
+
["!", :NOT],
|
83
|
+
|
84
|
+
["|", :BIT_OR],
|
85
|
+
["^", :BIT_XOR],
|
86
|
+
["&", :BIT_AND],
|
87
|
+
[">>>", :BIT_SRA],
|
88
|
+
[">>", :BIT_SRL],
|
89
|
+
["<<", :BIT_SLL],
|
90
|
+
|
91
|
+
["<", :CMP_LT],
|
92
|
+
[">", :CMP_GT],
|
93
|
+
|
94
|
+
["++", :INCR],
|
95
|
+
["--", :DECR],
|
96
|
+
|
97
|
+
["**", :EXP],
|
98
|
+
|
99
|
+
["+", :ADD],
|
100
|
+
["-", :SUB],
|
101
|
+
["*", :MUL],
|
102
|
+
["/", :DIV],
|
103
|
+
["%", :MOD],
|
104
|
+
|
105
|
+
["~", :BIT_NOT],
|
106
|
+
|
107
|
+
[".", :PERIOD],
|
108
|
+
[",", :COMMA],
|
109
|
+
[":", :COLON],
|
110
|
+
[";", :SEMICOLON],
|
111
|
+
["(", :LPAREN],
|
112
|
+
[")", :RPAREN],
|
113
|
+
["[", :LBRACK],
|
114
|
+
["]", :RBRACK],
|
115
|
+
["{", :LBRACE],
|
116
|
+
["}", :RBRACE]
|
117
|
+
]
|
118
|
+
|
119
|
+
def initialize!
|
120
|
+
return if @@initialized
|
121
|
+
|
122
|
+
# Convert the operators into a regex-compatible form.
|
123
|
+
@@operators = @@operators.map do |op, type|
|
124
|
+
[Regexp.new("^#{Regexp.escape(op)}"), op, type]
|
125
|
+
end
|
126
|
+
|
127
|
+
@@initialized = true
|
128
|
+
end
|
129
|
+
|
130
|
+
def initialize(code, path)
|
131
|
+
@code = code
|
132
|
+
|
133
|
+
# Perform one-time initialization of tokenizer data structures.
|
134
|
+
initialize!
|
135
|
+
|
136
|
+
# Create a context object that will be shared amongst all tokens for this
|
137
|
+
# code.
|
138
|
+
@ctx = Context.new(@code, path)
|
139
|
+
|
140
|
+
reset
|
141
|
+
end
|
142
|
+
|
143
|
+
def consume(num=1)
|
144
|
+
# Update the index of the character we're currently looking at.
|
145
|
+
@point += num
|
146
|
+
|
147
|
+
# Update the flag that indicates whether we've reached the file's end.
|
148
|
+
@eof = (@point >= @code.length)
|
149
|
+
|
150
|
+
# Update the the character we're examining currently.
|
151
|
+
@char = @code[@point]
|
152
|
+
|
153
|
+
# Extract the remainder of the line.
|
154
|
+
@line = @code[@point..@ctx.eol(@point)]
|
155
|
+
end
|
156
|
+
|
157
|
+
def reset
|
158
|
+
# Set tokenizer to initial state, ready to tokenize the code from the
|
159
|
+
# start.
|
160
|
+
@point = 0
|
161
|
+
consume(0)
|
162
|
+
skip
|
163
|
+
|
164
|
+
# Return tokenizer to allow method chaining.
|
165
|
+
self
|
166
|
+
end
|
167
|
+
|
168
|
+
def skip
|
169
|
+
while true do
|
170
|
+
whitespace = @line[/^(\s+|\s*#.*$)/]
|
171
|
+
return if whitespace.nil?
|
172
|
+
consume(whitespace.length)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def die(msg)
|
177
|
+
# We want the default context for token errors to be all lines that
|
178
|
+
# contain the region.
|
179
|
+
region = @ctx.bol(@mark)..@ctx.eol(@point)
|
180
|
+
bt = @ctx.context(@mark..@point + 1, region)
|
181
|
+
|
182
|
+
# Raise an exception with the context as our backtrace.
|
183
|
+
raise TokenException, msg, bt
|
184
|
+
end
|
185
|
+
|
186
|
+
def get_identifier
|
187
|
+
# Identifiers are composed of letters, digits, and underscores.
|
188
|
+
ident = @line[/^[_a-z][_a-z0-9]*/i]
|
189
|
+
consume(ident.length)
|
190
|
+
|
191
|
+
# Assume that we've got an identifier until proven otherwise.
|
192
|
+
type = :IDENT
|
193
|
+
|
194
|
+
# Identifiers may be prefixed with keywords. One example of a valid
|
195
|
+
# identifier is "break_". To ensure that we catch these cases, we
|
196
|
+
# initially parse all keywords as identifiers and then convert them as
|
197
|
+
# needed.
|
198
|
+
type = @@keywords[ident] if @@keywords.has_key? ident
|
199
|
+
|
200
|
+
return [type, ident]
|
201
|
+
end
|
202
|
+
|
203
|
+
def get_integer
|
204
|
+
# Try and parse the integer in any of three bases.
|
205
|
+
if @line =~ /^0x/i
|
206
|
+
# Hex integers start with "0x".
|
207
|
+
type = :INT_HEX
|
208
|
+
name = "hex"
|
209
|
+
regex1 = /^0x\w+/i
|
210
|
+
regex2 = /^0x[a-f0-9]+/i
|
211
|
+
elsif @line =~ /^0\w+/
|
212
|
+
# Octal integers start with "0".
|
213
|
+
type = :INT_OCT
|
214
|
+
name = "octal"
|
215
|
+
regex1 = /^0\w+/
|
216
|
+
regex2 = /^0[0-7]+/
|
217
|
+
else
|
218
|
+
# Anything else is a decimal integer.
|
219
|
+
type = :INT_DEC
|
220
|
+
name = "decimal"
|
221
|
+
regex1 = /^\w*/
|
222
|
+
regex2 = /^[0-9]+/
|
223
|
+
end
|
224
|
+
|
225
|
+
# First match with an overly permissive regex, and then match with the
|
226
|
+
# proper regex. If the permissive and restrictive versions don't match,
|
227
|
+
# then there's an error in the input.
|
228
|
+
permissive = @line[regex1]
|
229
|
+
restrictive = @line[regex2]
|
230
|
+
|
231
|
+
if permissive.nil? || restrictive.nil? || permissive != restrictive
|
232
|
+
# NASL interprets integers with a leading zero as octal if the only
|
233
|
+
# contain octal digits, and considers the integers as decimal otherwise.
|
234
|
+
type = :INT_DEC
|
235
|
+
regex2 = /^[0-9]+/
|
236
|
+
restrictive = @line[regex2]
|
237
|
+
end
|
238
|
+
|
239
|
+
if permissive.nil? || restrictive.nil? || permissive != restrictive
|
240
|
+
die("Invalid #{name} literal")
|
241
|
+
end
|
242
|
+
|
243
|
+
# If there was no problem, we use the restrictive version as the body of
|
244
|
+
# our integer.
|
245
|
+
integer = restrictive
|
246
|
+
|
247
|
+
consume(integer.length)
|
248
|
+
|
249
|
+
return [type, integer]
|
250
|
+
end
|
251
|
+
|
252
|
+
def get_string
|
253
|
+
unparsed = @code[@point..-1]
|
254
|
+
|
255
|
+
if @char == "'"
|
256
|
+
type = :DATA
|
257
|
+
|
258
|
+
# Single-quoted strings cannot have single-quotes stuffed inside them.
|
259
|
+
contents = unparsed[/\A'(\\.|[^'\\])*'/m]
|
260
|
+
die("Unterminated single-quoted string") if contents.nil?
|
261
|
+
else
|
262
|
+
type = :STRING
|
263
|
+
|
264
|
+
# Double-quoted strings cannot have double quotes stuffed inside them.
|
265
|
+
contents = unparsed[/\A"[^"]*"/m]
|
266
|
+
die("Unterminated double-quoted string") if contents.nil?
|
267
|
+
end
|
268
|
+
|
269
|
+
# Move the point forward over the string.
|
270
|
+
consume(contents.length)
|
271
|
+
|
272
|
+
# Remove the bounding quotes.
|
273
|
+
contents = contents[1..-2]
|
274
|
+
|
275
|
+
return [type, contents]
|
276
|
+
end
|
277
|
+
|
278
|
+
def get_operator
|
279
|
+
# These are all of the operators defined in NASL. Their order is vitally
|
280
|
+
# important.
|
281
|
+
@@operators.each do |regex, op, type|
|
282
|
+
next if @line !~ regex
|
283
|
+
consume(op.length)
|
284
|
+
return [type, op]
|
285
|
+
end
|
286
|
+
|
287
|
+
return nil
|
288
|
+
end
|
289
|
+
|
290
|
+
def get_token
|
291
|
+
# Make sure we're not at the end of the file.
|
292
|
+
return [false, Token.new(:EOF, "$", @point...@point, @ctx)] if @eof
|
293
|
+
|
294
|
+
# Save our starting point, which to use Emacs terminology is called the
|
295
|
+
# 'mark'.
|
296
|
+
@mark = @point
|
297
|
+
|
298
|
+
# Try to parse token at the point.
|
299
|
+
token = if @char =~ /[_a-z]/i
|
300
|
+
get_identifier
|
301
|
+
elsif @char =~ /['"]/
|
302
|
+
get_string
|
303
|
+
elsif @char =~ /[0-9]/
|
304
|
+
get_integer
|
305
|
+
else
|
306
|
+
get_operator
|
307
|
+
end
|
308
|
+
|
309
|
+
# Everything in the language is enumerated by the above functions, so if
|
310
|
+
# we get here without a token parsed, the input file is invalid.
|
311
|
+
die("Invalid character ('#@char')") if token.nil?
|
312
|
+
skip
|
313
|
+
|
314
|
+
return [token.first, Token.new(*token, @mark...@point, @ctx)]
|
315
|
+
end
|
316
|
+
|
317
|
+
def get_tokens
|
318
|
+
tokens = []
|
319
|
+
|
320
|
+
until @eof
|
321
|
+
tokens << get_token
|
322
|
+
end
|
323
|
+
|
324
|
+
return tokens
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
data/lib/nasl/version.rb
ADDED