nasl 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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