antlr3 1.8.0 → 1.8.2
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/History.txt +35 -0
- data/Manifest.txt +73 -0
- data/README.txt +6 -13
- data/java/RubyTarget.java +43 -19
- data/java/antlr-full-3.2.1.jar +0 -0
- data/lib/antlr3/debug.rb +2 -0
- data/lib/antlr3/debug/event-hub.rb +55 -55
- data/lib/antlr3/debug/record-event-listener.rb +2 -2
- data/lib/antlr3/debug/rule-tracer.rb +14 -14
- data/lib/antlr3/debug/socket.rb +47 -47
- data/lib/antlr3/debug/trace-event-listener.rb +8 -8
- data/lib/antlr3/main.rb +29 -9
- data/lib/antlr3/modes/ast-builder.rb +7 -7
- data/lib/antlr3/modes/filter.rb +19 -17
- data/lib/antlr3/profile.rb +34 -6
- data/lib/antlr3/recognizers.rb +50 -1
- data/lib/antlr3/streams.rb +19 -15
- data/lib/antlr3/streams/rewrite.rb +241 -229
- data/lib/antlr3/template/group-file-lexer.rb +6 -8
- data/lib/antlr3/template/group-file-parser.rb +16 -16
- data/lib/antlr3/template/group-file.rb +1 -1
- data/lib/antlr3/test/call-stack.rb +13 -13
- data/lib/antlr3/test/core-extensions.rb +69 -69
- data/lib/antlr3/test/functional.rb +0 -4
- data/lib/antlr3/test/grammar.rb +70 -70
- data/lib/antlr3/token.rb +41 -17
- data/lib/antlr3/tree.rb +11 -14
- data/lib/antlr3/tree/debug.rb +53 -53
- data/lib/antlr3/tree/visitor.rb +11 -11
- data/lib/antlr3/tree/wizard.rb +35 -35
- data/lib/antlr3/util.rb +18 -0
- data/lib/antlr3/version.rb +1 -1
- data/rakefile +1 -0
- data/samples/ANTLRv3Grammar.g +3 -3
- data/samples/JavaScript.g +702 -0
- data/samples/standard/C/C.g +543 -0
- data/samples/standard/C/C.tokens +175 -0
- data/samples/standard/C/C__testrig.st +0 -0
- data/samples/standard/C/c.rb +12 -0
- data/samples/standard/C/input +3479 -0
- data/samples/standard/C/output +171 -0
- data/samples/standard/LL-star/LLStar.g +101 -0
- data/samples/standard/LL-star/input +12 -0
- data/samples/standard/LL-star/ll-star.rb +12 -0
- data/samples/standard/LL-star/output +2 -0
- data/samples/standard/calc/Calculator.g +47 -0
- data/samples/standard/calc/Calculator.py +16 -0
- data/samples/standard/calc/Calculator.rb +28 -0
- data/samples/standard/cminus/CMinus.g +141 -0
- data/samples/standard/cminus/bytecode.group +80 -0
- data/samples/standard/cminus/cminus.rb +16 -0
- data/samples/standard/cminus/input +9 -0
- data/samples/standard/cminus/java.group +91 -0
- data/samples/standard/cminus/output +11 -0
- data/samples/standard/cminus/python.group +48 -0
- data/samples/standard/dynamic-scope/DynamicScopes.g +50 -0
- data/samples/standard/dynamic-scope/dynamic-scopes.rb +12 -0
- data/samples/standard/dynamic-scope/input +7 -0
- data/samples/standard/dynamic-scope/output +4 -0
- data/samples/standard/fuzzy/FuzzyJava.g +89 -0
- data/samples/standard/fuzzy/fuzzy.py +11 -0
- data/samples/standard/fuzzy/fuzzy.rb +9 -0
- data/samples/standard/fuzzy/input +13 -0
- data/samples/standard/fuzzy/output +12 -0
- data/samples/standard/hoisted-predicates/HoistedPredicates.g +40 -0
- data/samples/standard/hoisted-predicates/hoisted-predicates.rb +13 -0
- data/samples/standard/hoisted-predicates/input +1 -0
- data/samples/standard/hoisted-predicates/output +1 -0
- data/samples/standard/island-grammar/Javadoc.g +46 -0
- data/samples/standard/island-grammar/Simple.g +104 -0
- data/samples/standard/island-grammar/input +11 -0
- data/samples/standard/island-grammar/island.rb +12 -0
- data/samples/standard/island-grammar/output +16 -0
- data/samples/standard/java/Java.g +827 -0
- data/samples/standard/java/input +80 -0
- data/samples/standard/java/java.rb +13 -0
- data/samples/standard/java/output +1 -0
- data/samples/standard/python/Python.g +718 -0
- data/samples/standard/python/PythonTokenSource.rb +107 -0
- data/samples/standard/python/input +210 -0
- data/samples/standard/python/output +24 -0
- data/samples/standard/python/python.rb +14 -0
- data/samples/standard/rakefile +18 -0
- data/samples/standard/scopes/SymbolTable.g +66 -0
- data/samples/standard/scopes/input +12 -0
- data/samples/standard/scopes/output +3 -0
- data/samples/standard/scopes/scopes.rb +12 -0
- data/samples/standard/simplecTreeParser/SimpleC.g +113 -0
- data/samples/standard/simplecTreeParser/SimpleCWalker.g +64 -0
- data/samples/standard/simplecTreeParser/input +12 -0
- data/samples/standard/simplecTreeParser/output +1 -0
- data/samples/standard/simplecTreeParser/simplec.rb +18 -0
- data/samples/standard/treeparser/Lang.g +24 -0
- data/samples/standard/treeparser/LangDumpDecl.g +17 -0
- data/samples/standard/treeparser/input +1 -0
- data/samples/standard/treeparser/output +2 -0
- data/samples/standard/treeparser/treeparser.rb +18 -0
- data/samples/standard/tweak/Tweak.g +68 -0
- data/samples/standard/tweak/input +9 -0
- data/samples/standard/tweak/output +16 -0
- data/samples/standard/tweak/tweak.rb +13 -0
- data/samples/standard/xml/README +16 -0
- data/samples/standard/xml/XML.g +123 -0
- data/samples/standard/xml/input +21 -0
- data/samples/standard/xml/output +39 -0
- data/samples/standard/xml/xml.rb +9 -0
- data/templates/Ruby.stg +4 -4
- data/test/functional/ast-output/auto-ast.rb +0 -5
- data/test/functional/ast-output/rewrites.rb +4 -4
- data/test/unit/test-scope.rb +45 -0
- metadata +96 -8
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
#!/usr/bin/ruby
|
|
2
|
+
# encoding: utf-8
|
|
3
|
+
|
|
4
|
+
module Python
|
|
5
|
+
unless defined?(TokenData)
|
|
6
|
+
require 'PythonLexer'
|
|
7
|
+
require 'PythonParser'
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
class TokenSource
|
|
11
|
+
include ANTLR3::TokenSource
|
|
12
|
+
include ANTLR3::Constants
|
|
13
|
+
include TokenData
|
|
14
|
+
|
|
15
|
+
def initialize(lexer)
|
|
16
|
+
@lexer = lexer
|
|
17
|
+
@indent_stack = []
|
|
18
|
+
@eof = nil
|
|
19
|
+
@token_queue = []
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def next_token
|
|
23
|
+
queue_tokens if @token_queue.empty? and @eof.nil?
|
|
24
|
+
return @token_queue.shift || @eof
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def queue_tokens
|
|
28
|
+
begin
|
|
29
|
+
t = fetch or return false
|
|
30
|
+
@token_queue << t
|
|
31
|
+
end until t.type == NEWLINE
|
|
32
|
+
|
|
33
|
+
while t = fetch and t.hidden?
|
|
34
|
+
# skip past things like comments
|
|
35
|
+
@token_queue << t
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
if t.nil? # EOF
|
|
39
|
+
if prior = (@token_queue.last || @eof)
|
|
40
|
+
line = prior.line || 0
|
|
41
|
+
column = prior.column + prior.text.to_s.length rescue -1
|
|
42
|
+
else
|
|
43
|
+
line, column = 0, -1
|
|
44
|
+
end
|
|
45
|
+
insert_indentation(0, line, column)
|
|
46
|
+
elsif t.type == LEADING_WS
|
|
47
|
+
t.channel = ANTLR3::HIDDEN_CHANNEL
|
|
48
|
+
@token_queue << t
|
|
49
|
+
width = measure(t.text)
|
|
50
|
+
insert_indentation(width, t.line, t.column)
|
|
51
|
+
else
|
|
52
|
+
insert_indentation(0, t.line, t.column)
|
|
53
|
+
@token_queue << t
|
|
54
|
+
end
|
|
55
|
+
return true
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def insert_indentation(width, line, col)
|
|
59
|
+
case width <=> current_indent
|
|
60
|
+
when 1 # an indent
|
|
61
|
+
@indent_stack.push(width)
|
|
62
|
+
tk = Token.new(INDENT, DEFAULT, '')
|
|
63
|
+
tk.line = line
|
|
64
|
+
tk.column = col
|
|
65
|
+
@token_queue << tk
|
|
66
|
+
when -1 # a dedent
|
|
67
|
+
begin
|
|
68
|
+
@indent_stack.pop || break
|
|
69
|
+
tk = Token.new(DEDENT, DEFAULT, '')
|
|
70
|
+
tk.line = line
|
|
71
|
+
tk.column = col
|
|
72
|
+
@token_queue << tk
|
|
73
|
+
end until current_indent <= width
|
|
74
|
+
when 0 # same level
|
|
75
|
+
# do nothing
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def current_indent
|
|
80
|
+
@indent_stack.last || 0
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def measure(space)
|
|
84
|
+
size = 0
|
|
85
|
+
space.each_byte do |char|
|
|
86
|
+
case char
|
|
87
|
+
when ?\s then size += 1
|
|
88
|
+
when ?\t
|
|
89
|
+
size += 8
|
|
90
|
+
size -= size % 8
|
|
91
|
+
else break
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
return size
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def fetch
|
|
98
|
+
@eof and return nil
|
|
99
|
+
t = @lexer.next_token
|
|
100
|
+
if t.nil? or t.type == EOF
|
|
101
|
+
@eof = t || EOFToken
|
|
102
|
+
return nil
|
|
103
|
+
end
|
|
104
|
+
return t
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"""This is a substantially improved version of the older Interpreter.py demo
|
|
2
|
+
It creates a simple GUI JPython console window with simple history
|
|
3
|
+
as well as the ability to interupt running code (with the ESC key).
|
|
4
|
+
|
|
5
|
+
Like Interpreter.py, this is still just a demo, and needs substantial
|
|
6
|
+
work before serious use.
|
|
7
|
+
|
|
8
|
+
Thanks to Geza Groma (groma@everx.szbk.u-szeged.hu) for several valuable
|
|
9
|
+
ideas for this tool -- his JPConsole is a more refined implementation
|
|
10
|
+
of similar ideas.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from Styles import Styles
|
|
14
|
+
from Keymap import Keymap
|
|
15
|
+
|
|
16
|
+
from pawt import swing, colors
|
|
17
|
+
from java.awt.event.KeyEvent import VK_UP, VK_DOWN
|
|
18
|
+
from java.awt.event import ActionEvent
|
|
19
|
+
from java.lang import Thread, System
|
|
20
|
+
from code import compile_command
|
|
21
|
+
import string, sys, re
|
|
22
|
+
|
|
23
|
+
class OutputBuffer:
|
|
24
|
+
def __init__(self, console, stylename):
|
|
25
|
+
self.console = console
|
|
26
|
+
self.stylename = stylename
|
|
27
|
+
|
|
28
|
+
def flush(self):
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
def write(self, text):
|
|
32
|
+
self.console.write(text, self.stylename)
|
|
33
|
+
|
|
34
|
+
class Console:
|
|
35
|
+
def __init__(self, styles=None, keymap=None):
|
|
36
|
+
if styles is None:
|
|
37
|
+
styles = Styles()
|
|
38
|
+
basic = styles.add('normal', tabsize=3, fontSize=12, fontFamily="Courier")
|
|
39
|
+
styles.add('error', parent=basic, foreground=colors.red)
|
|
40
|
+
styles.add('output', parent=basic, foreground=colors.blue)
|
|
41
|
+
styles.add('input', parent=basic, foreground=colors.black)
|
|
42
|
+
styles.add('prompt', parent=basic, foreground=colors.purple)
|
|
43
|
+
self.styles = styles
|
|
44
|
+
|
|
45
|
+
# This is a hack to get at an inner class
|
|
46
|
+
# This will not be required in JPython-1.1
|
|
47
|
+
ForegroundAction = getattr(swing.text, 'StyledEditorKit$ForegroundAction')
|
|
48
|
+
self.inputAction = ForegroundAction("start input", colors.black)
|
|
49
|
+
|
|
50
|
+
if keymap is None:
|
|
51
|
+
keymap = Keymap()
|
|
52
|
+
keymap.bind('enter', self.enter)
|
|
53
|
+
keymap.bind('tab', self.tab)
|
|
54
|
+
keymap.bind('escape', self.escape)
|
|
55
|
+
keymap.bind('up', self.uphistory)
|
|
56
|
+
keymap.bind('down', self.downhistory)
|
|
57
|
+
|
|
58
|
+
self.keymap = keymap
|
|
59
|
+
|
|
60
|
+
self.document = swing.text.DefaultStyledDocument(self.styles)
|
|
61
|
+
self.document.setLogicalStyle(0, self.styles.get('normal'))
|
|
62
|
+
|
|
63
|
+
self.textpane = swing.JTextPane(self.document)
|
|
64
|
+
self.textpane.keymap = self.keymap
|
|
65
|
+
|
|
66
|
+
self.history = []
|
|
67
|
+
self.oldHistoryLength = 0
|
|
68
|
+
self.historyPosition = 0
|
|
69
|
+
|
|
70
|
+
self.command = []
|
|
71
|
+
self.locals = {}
|
|
72
|
+
|
|
73
|
+
def write(self, text, stylename='normal'):
|
|
74
|
+
style = self.styles.get(stylename)
|
|
75
|
+
self.document.insertString(self.document.length, text, style)
|
|
76
|
+
|
|
77
|
+
def beep(self):
|
|
78
|
+
self.textpane.toolkit.beep()
|
|
79
|
+
|
|
80
|
+
def startUserInput(self, prompt=None):
|
|
81
|
+
if prompt is not None:
|
|
82
|
+
self.write(prompt, 'prompt')
|
|
83
|
+
self.startInput = self.document.createPosition(self.document.length-1)
|
|
84
|
+
#self.document.setCharacterAttributes(self.document.length-1, 1, self.styles.get('input'), 1)
|
|
85
|
+
self.textpane.caretPosition = self.document.length
|
|
86
|
+
ae = ActionEvent(self.textpane, ActionEvent.ACTION_PERFORMED, 'start input')
|
|
87
|
+
self.inputAction.actionPerformed(ae)
|
|
88
|
+
|
|
89
|
+
def getinput(self):
|
|
90
|
+
offset = self.startInput.offset
|
|
91
|
+
line = self.document.getText(offset+1, self.document.length-offset)
|
|
92
|
+
return string.rstrip(line)
|
|
93
|
+
|
|
94
|
+
def replaceinput(self, text):
|
|
95
|
+
offset = self.startInput.offset + 1
|
|
96
|
+
self.document.remove(offset, self.document.length-offset)
|
|
97
|
+
self.write(text, 'input')
|
|
98
|
+
|
|
99
|
+
def enter(self):
|
|
100
|
+
line = self.getinput()
|
|
101
|
+
self.write('\n', 'input')
|
|
102
|
+
|
|
103
|
+
self.history.append(line)
|
|
104
|
+
self.handleLine(line)
|
|
105
|
+
|
|
106
|
+
def gethistory(self, direction):
|
|
107
|
+
historyLength = len(self.history)
|
|
108
|
+
if self.oldHistoryLength < historyLength:
|
|
109
|
+
# new line was entered after last call
|
|
110
|
+
self.oldHistoryLength = historyLength
|
|
111
|
+
if self.history[self.historyPosition] != self.history[-1]:
|
|
112
|
+
self.historyPosition = historyLength
|
|
113
|
+
|
|
114
|
+
pos = self.historyPosition + direction
|
|
115
|
+
|
|
116
|
+
if 0 <= pos < historyLength:
|
|
117
|
+
self.historyPosition = pos
|
|
118
|
+
self.replaceinput(self.history[pos])
|
|
119
|
+
else:
|
|
120
|
+
self.beep()
|
|
121
|
+
|
|
122
|
+
def uphistory(self):
|
|
123
|
+
self.gethistory(-1)
|
|
124
|
+
|
|
125
|
+
def downhistory(self):
|
|
126
|
+
self.gethistory(1)
|
|
127
|
+
|
|
128
|
+
def tab(self):
|
|
129
|
+
self.write('\t', 'input')
|
|
130
|
+
|
|
131
|
+
def escape(self):
|
|
132
|
+
if (not hasattr(self, 'pythonThread') or self.pythonThread is None or not self.pythonThread.alive):
|
|
133
|
+
self.beep()
|
|
134
|
+
return
|
|
135
|
+
|
|
136
|
+
self.pythonThread.stopPython()
|
|
137
|
+
|
|
138
|
+
def capturePythonOutput(self, stdoutStyle='output', stderrStyle='error'):
|
|
139
|
+
import sys
|
|
140
|
+
sys.stdout = OutputBuffer(self, stdoutStyle)
|
|
141
|
+
sys.stderr = OutputBuffer(self, stderrStyle)
|
|
142
|
+
|
|
143
|
+
def handleLine(self, text):
|
|
144
|
+
self.command.append(text)
|
|
145
|
+
|
|
146
|
+
try:
|
|
147
|
+
code = compile_command(string.join(self.command, '\n'))
|
|
148
|
+
except SyntaxError:
|
|
149
|
+
traceback.print_exc(0)
|
|
150
|
+
self.command = []
|
|
151
|
+
self.startUserInput(str(sys.ps1)+'\t')
|
|
152
|
+
return
|
|
153
|
+
|
|
154
|
+
if code is None:
|
|
155
|
+
self.startUserInput(str(sys.ps2)+'\t')
|
|
156
|
+
return
|
|
157
|
+
|
|
158
|
+
self.command = []
|
|
159
|
+
|
|
160
|
+
pt = PythonThread(code, self)
|
|
161
|
+
self.pythonThread = pt
|
|
162
|
+
pt.start()
|
|
163
|
+
|
|
164
|
+
def newInput(self):
|
|
165
|
+
self.startUserInput(str(sys.ps1)+'\t')
|
|
166
|
+
|
|
167
|
+
import traceback
|
|
168
|
+
|
|
169
|
+
class PythonThread(Thread):
|
|
170
|
+
def __init__(self, code, console):
|
|
171
|
+
self.code = code
|
|
172
|
+
self.console = console
|
|
173
|
+
self.locals = console.locals
|
|
174
|
+
|
|
175
|
+
def run(self):
|
|
176
|
+
try:
|
|
177
|
+
exec self.code in self.locals
|
|
178
|
+
|
|
179
|
+
#Include these lines to actually exit on a sys.exit() call
|
|
180
|
+
#except SystemExit, value:
|
|
181
|
+
# raise SystemExit, value
|
|
182
|
+
|
|
183
|
+
except:
|
|
184
|
+
exc_type, exc_value, exc_traceback = sys.exc_info()
|
|
185
|
+
l = len(traceback.extract_tb(sys.exc_traceback))
|
|
186
|
+
try:
|
|
187
|
+
1/0
|
|
188
|
+
except:
|
|
189
|
+
m = len(traceback.extract_tb(sys.exc_traceback))
|
|
190
|
+
traceback.print_exception(exc_type, exc_value, exc_traceback, l-m)
|
|
191
|
+
|
|
192
|
+
self.console.newInput()
|
|
193
|
+
|
|
194
|
+
def stopPython(self):
|
|
195
|
+
#Should spend 2 seconds trying to kill thread in nice Python style first...
|
|
196
|
+
self.stop()
|
|
197
|
+
|
|
198
|
+
header = """\
|
|
199
|
+
JPython %(version)s on %(platform)s
|
|
200
|
+
%(copyright)s
|
|
201
|
+
""" % {'version':sys.version, 'platform':sys.platform, 'copyright':sys.copyright}
|
|
202
|
+
|
|
203
|
+
if __name__ == '__main__':
|
|
204
|
+
c = Console()
|
|
205
|
+
pane = swing.JScrollPane(c.textpane)
|
|
206
|
+
swing.test(pane, size=(500,400), name='JPython Console')
|
|
207
|
+
c.write(header, 'output')
|
|
208
|
+
c.capturePythonOutput()
|
|
209
|
+
c.textpane.requestFocus()
|
|
210
|
+
c.newInput()
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
found method def __init__
|
|
2
|
+
found method def flush
|
|
3
|
+
found method def write
|
|
4
|
+
found class def OutputBuffer
|
|
5
|
+
found method def __init__
|
|
6
|
+
found method def write
|
|
7
|
+
found method def beep
|
|
8
|
+
found method def startUserInput
|
|
9
|
+
found method def getinput
|
|
10
|
+
found method def replaceinput
|
|
11
|
+
found method def enter
|
|
12
|
+
found method def gethistory
|
|
13
|
+
found method def uphistory
|
|
14
|
+
found method def downhistory
|
|
15
|
+
found method def tab
|
|
16
|
+
found method def escape
|
|
17
|
+
found method def capturePythonOutput
|
|
18
|
+
found method def handleLine
|
|
19
|
+
found method def newInput
|
|
20
|
+
found class def Console
|
|
21
|
+
found method def __init__
|
|
22
|
+
found method def run
|
|
23
|
+
found method def stopPython
|
|
24
|
+
found class def PythonThread
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/ruby
|
|
2
|
+
# encoding: utf-8
|
|
3
|
+
$:.unshift( File.dirname( __FILE__ ) )
|
|
4
|
+
require 'PythonLexer'
|
|
5
|
+
require 'PythonParser'
|
|
6
|
+
require 'PythonTokenSource'
|
|
7
|
+
|
|
8
|
+
for file in ARGV
|
|
9
|
+
input = ANTLR3::FileStream.new( file )
|
|
10
|
+
lexer = Python::Lexer.new( input )
|
|
11
|
+
source = Python::TokenSource.new( lexer )
|
|
12
|
+
parser = Python::Parser.new( source )
|
|
13
|
+
parser.file_input
|
|
14
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/ruby
|
|
2
|
+
# encoding: utf-8
|
|
3
|
+
|
|
4
|
+
load '../../config/antlr3.rb'
|
|
5
|
+
require 'antlr3/task'
|
|
6
|
+
|
|
7
|
+
ANTLR3::CompileTask.define do | t |
|
|
8
|
+
for dir in Dir[ '*/' ]
|
|
9
|
+
grammars = Dir[ dir / '*.g' ]
|
|
10
|
+
t.grammar_set( grammars, :output_directory => dir )
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
desc( "compile all example grammars" )
|
|
15
|
+
task( :default => 'antlr-grammars:compile' )
|
|
16
|
+
|
|
17
|
+
desc( "trash all generated output" )
|
|
18
|
+
task( :clean => 'antlr-grammars:clobber' )
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
grammar SymbolTable;
|
|
2
|
+
|
|
3
|
+
options { language = Ruby; }
|
|
4
|
+
|
|
5
|
+
/* Scope of symbol names. Both globals and block rules need to push a new
|
|
6
|
+
* symbol table upon entry and they must use the same stack. So, I must
|
|
7
|
+
* define a global scope and say that globals and block use this by saying
|
|
8
|
+
* 'scope Symbols;' in those rule definitions.
|
|
9
|
+
*/
|
|
10
|
+
scope Symbols {
|
|
11
|
+
names
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@init {
|
|
15
|
+
@level = 0
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
prog: globals (method)*
|
|
19
|
+
;
|
|
20
|
+
|
|
21
|
+
globals
|
|
22
|
+
scope Symbols;
|
|
23
|
+
@init {
|
|
24
|
+
@level += 1
|
|
25
|
+
$Symbols::names = []
|
|
26
|
+
}
|
|
27
|
+
: (decl)*
|
|
28
|
+
{
|
|
29
|
+
puts( "globals: [#{ $Symbols::names.join( ', ' ) }]" )
|
|
30
|
+
@level -= 1
|
|
31
|
+
}
|
|
32
|
+
;
|
|
33
|
+
|
|
34
|
+
method
|
|
35
|
+
: 'method' ID '(' ')' block
|
|
36
|
+
;
|
|
37
|
+
|
|
38
|
+
block
|
|
39
|
+
scope Symbols;
|
|
40
|
+
@init {
|
|
41
|
+
@level += 1
|
|
42
|
+
$Symbols::names = []
|
|
43
|
+
}
|
|
44
|
+
: '{' (decl)* (stat)* '}'
|
|
45
|
+
{
|
|
46
|
+
puts( "level #@level symbols: [#{ $Symbols::names.join( ', ' ) }]" )
|
|
47
|
+
@level -= 1
|
|
48
|
+
}
|
|
49
|
+
;
|
|
50
|
+
|
|
51
|
+
stat: ID '=' INT ';'
|
|
52
|
+
| block
|
|
53
|
+
;
|
|
54
|
+
|
|
55
|
+
decl: 'int' ID ';'
|
|
56
|
+
{ $Symbols::names << $ID } // add to current symbol table
|
|
57
|
+
;
|
|
58
|
+
|
|
59
|
+
ID : ('a'..'z')+
|
|
60
|
+
;
|
|
61
|
+
|
|
62
|
+
INT : ('0'..'9')+
|
|
63
|
+
;
|
|
64
|
+
|
|
65
|
+
WS : (' '|'\n'|'\r')+ {$channel=HIDDEN}
|
|
66
|
+
;
|