crokus 0.0.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.
- checksums.yaml +7 -0
- data/bin/crokus +5 -0
- data/lib/crokus.rb +4 -0
- data/lib/crokus/ast.rb +431 -0
- data/lib/crokus/ast_printer.rb +86 -0
- data/lib/crokus/cfg.rb +81 -0
- data/lib/crokus/cfg_builder.rb +169 -0
- data/lib/crokus/cfg_cleaner.rb +62 -0
- data/lib/crokus/cfg_printer.rb +73 -0
- data/lib/crokus/cleaner.rb +10 -0
- data/lib/crokus/code.rb +46 -0
- data/lib/crokus/compiler.rb +124 -0
- data/lib/crokus/generic_lexer.rb +62 -0
- data/lib/crokus/indent.rb +19 -0
- data/lib/crokus/ir_dumper.rb +48 -0
- data/lib/crokus/lexer.rb +113 -0
- data/lib/crokus/parser.rb +1072 -0
- data/lib/crokus/parser_only.rb +993 -0
- data/lib/crokus/pretty_printer.rb +443 -0
- data/lib/crokus/runner.rb +86 -0
- data/lib/crokus/tac_builder.rb +109 -0
- data/lib/crokus/token.rb +43 -0
- data/lib/crokus/transformer.rb +304 -0
- data/lib/crokus/version.rb +3 -0
- data/lib/crokus/visitor.rb +341 -0
- metadata +70 -0
data/lib/crokus/code.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
class Code
|
2
|
+
|
3
|
+
attr_accessor :indent,:lines
|
4
|
+
|
5
|
+
def initialize str=nil
|
6
|
+
@lines=[]
|
7
|
+
(@lines << str) if str
|
8
|
+
@indent=0
|
9
|
+
end
|
10
|
+
|
11
|
+
def <<(thing)
|
12
|
+
if (code=thing).is_a? Code
|
13
|
+
code.lines.each do |line|
|
14
|
+
@lines << " "*@indent+line.to_s
|
15
|
+
end
|
16
|
+
elsif thing.is_a? Array
|
17
|
+
thing.each do |kode|
|
18
|
+
@lines << kode
|
19
|
+
end
|
20
|
+
elsif thing.nil?
|
21
|
+
else
|
22
|
+
@lines << " "*@indent+thing.to_s
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def finalize
|
27
|
+
return @lines.join("\n") if @lines.any?
|
28
|
+
""
|
29
|
+
end
|
30
|
+
|
31
|
+
def newline
|
32
|
+
@lines << " "
|
33
|
+
end
|
34
|
+
|
35
|
+
def save_as filename,verbose=true,sep="\n"
|
36
|
+
str=self.finalize
|
37
|
+
File.open(filename,'w'){|f| f.puts(str)}
|
38
|
+
return filename
|
39
|
+
end
|
40
|
+
|
41
|
+
def size
|
42
|
+
@lines.size
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require_relative 'ast'
|
2
|
+
require_relative 'ast_printer'
|
3
|
+
require_relative 'parser'
|
4
|
+
#require_relative 'parser_only'
|
5
|
+
require_relative 'visitor'
|
6
|
+
require_relative 'transformer'
|
7
|
+
require_relative 'pretty_printer'
|
8
|
+
require_relative 'cfg_builder'
|
9
|
+
require_relative 'tac_builder'
|
10
|
+
require_relative 'ir_dumper'
|
11
|
+
|
12
|
+
module Crokus
|
13
|
+
|
14
|
+
class Compiler
|
15
|
+
|
16
|
+
attr_accessor :options
|
17
|
+
attr_accessor :parser
|
18
|
+
attr_accessor :ast
|
19
|
+
attr_accessor :base_name
|
20
|
+
|
21
|
+
def initialize
|
22
|
+
@options={}
|
23
|
+
$options=@options
|
24
|
+
@parser=Parser.new
|
25
|
+
end
|
26
|
+
|
27
|
+
def header
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
def compile filename
|
32
|
+
header
|
33
|
+
|
34
|
+
parse(filename)
|
35
|
+
if options[:parse_only]
|
36
|
+
return true
|
37
|
+
end
|
38
|
+
|
39
|
+
build_cfg
|
40
|
+
if options[:cfg]
|
41
|
+
return true
|
42
|
+
end
|
43
|
+
|
44
|
+
build_tac
|
45
|
+
if options[:tac]
|
46
|
+
return true
|
47
|
+
end
|
48
|
+
|
49
|
+
emit_ir
|
50
|
+
return true
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
|
55
|
+
def parse filename
|
56
|
+
@base_name=File.basename(filename, ".c")
|
57
|
+
code=IO.read(filename)
|
58
|
+
puts "=> parsing #{filename}" unless options[:mute]
|
59
|
+
@ast=Parser.new.parse(code)
|
60
|
+
draw_ast if options[:draw_ast]
|
61
|
+
pretty_print if options[:pp]
|
62
|
+
end
|
63
|
+
|
64
|
+
# def parse filename
|
65
|
+
# @base_name=File.basename(filename, ".c")
|
66
|
+
# code=IO.read(filename)
|
67
|
+
# @ast=Parser.new.parse(code)
|
68
|
+
# end
|
69
|
+
|
70
|
+
def draw_ast tree=nil,filename=nil
|
71
|
+
dotname=filename || "#{base_name}.dot"
|
72
|
+
puts " |--> drawing AST '#{dotname}'" unless options[:mute]
|
73
|
+
ast_ = tree || @ast
|
74
|
+
dot=AstPrinter.new.print(ast_)
|
75
|
+
dot.save_as dotname
|
76
|
+
end
|
77
|
+
|
78
|
+
def transform
|
79
|
+
puts "=> dummy transform" unless options[:mute]
|
80
|
+
ast_t= Transformer.new.transform(ast)
|
81
|
+
dotname="#{base_name}_trans.dot"
|
82
|
+
draw_ast ast_t,dotname
|
83
|
+
end
|
84
|
+
|
85
|
+
def visit
|
86
|
+
puts "=> dummy visit" unless options[:mute]
|
87
|
+
Visitor.new.visit(ast)
|
88
|
+
end
|
89
|
+
|
90
|
+
def pretty_print
|
91
|
+
puts "=> pretty_print" unless options[:mute]
|
92
|
+
code=PrettyPrinter.new.visit(ast)
|
93
|
+
pp_c=@base_name+"_pp.c"
|
94
|
+
File.open(pp_c,'w'){|f| f.puts code}
|
95
|
+
puts " |--> saved as #{pp_c}" unless options[:mute]
|
96
|
+
end
|
97
|
+
|
98
|
+
def build_cfg
|
99
|
+
puts "=> building CFGs" unless options[:mute]
|
100
|
+
builder=CFGBuilder.new
|
101
|
+
builder.build(@ast)
|
102
|
+
end
|
103
|
+
|
104
|
+
def build_tac
|
105
|
+
puts "=> building TAC" unless options[:mute]
|
106
|
+
builder=TACBuilder.new
|
107
|
+
builder.visit(@ast)
|
108
|
+
end
|
109
|
+
|
110
|
+
def emit_ir
|
111
|
+
puts "=> emit textual IR " unless options[:mute]
|
112
|
+
IRDumper.new.visit(@ast)
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
end
|
117
|
+
#
|
118
|
+
# if $PROGRAM_NAME == __FILE__
|
119
|
+
# filename=ARGV[0]
|
120
|
+
# t1 = Time.now
|
121
|
+
# C::Compiler.new.compile(filename)
|
122
|
+
# t2 = Time.now
|
123
|
+
# puts "parsed in : #{t2-t1} s"
|
124
|
+
# end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'strscan'
|
2
|
+
|
3
|
+
require_relative 'token'
|
4
|
+
|
5
|
+
class GenericLexer
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@rules = []
|
9
|
+
@rules << [:newline,/[\n]/]
|
10
|
+
end
|
11
|
+
|
12
|
+
def ignore pattern
|
13
|
+
@rules << [:skip,pattern]
|
14
|
+
end
|
15
|
+
|
16
|
+
def keyword str
|
17
|
+
@rules.unshift [str.to_sym,/#{str}\b/]
|
18
|
+
end
|
19
|
+
|
20
|
+
def token h_token_pattern
|
21
|
+
token,pattern=*h_token_pattern.to_a.first
|
22
|
+
@rules << [token, pattern]
|
23
|
+
end
|
24
|
+
|
25
|
+
def open code
|
26
|
+
@ssc = StringScanner.new code
|
27
|
+
@line=0
|
28
|
+
end
|
29
|
+
|
30
|
+
def next_token
|
31
|
+
return [nil,nil,nil] if @ssc.empty?
|
32
|
+
tok = get_token
|
33
|
+
return (tok.is_a? :skip) ? next_token : tok
|
34
|
+
end
|
35
|
+
|
36
|
+
def get_token
|
37
|
+
linecol=position()
|
38
|
+
@rules.each do |rule, regexp|
|
39
|
+
val = @ssc.scan(regexp)
|
40
|
+
return Token.new([rule, val, linecol]) if val
|
41
|
+
end
|
42
|
+
raise "lexing error line #{linecol.first} around '#{@ssc.peek(10)}' "
|
43
|
+
end
|
44
|
+
|
45
|
+
def position
|
46
|
+
if @ssc.bol?
|
47
|
+
@line+=1
|
48
|
+
@old_pos=@ssc.pos
|
49
|
+
end
|
50
|
+
[@line,@ssc.pos-@old_pos+1]
|
51
|
+
end
|
52
|
+
|
53
|
+
def tokenize code
|
54
|
+
open(code)
|
55
|
+
tokens=[]
|
56
|
+
tokens << next_token() while not @ssc.eos?
|
57
|
+
# while not @ssc.eos?
|
58
|
+
# tokens << (p next_token)
|
59
|
+
# end
|
60
|
+
tokens
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Crokus
|
2
|
+
|
3
|
+
class IRDumper < Visitor
|
4
|
+
|
5
|
+
def visitFunction func,args=nil
|
6
|
+
puts "IR for '#{func.name}'".center(40,'=')
|
7
|
+
dump func.cfg
|
8
|
+
end
|
9
|
+
|
10
|
+
def dump cfg
|
11
|
+
@visited=[]
|
12
|
+
visit_rec cfg.starter
|
13
|
+
end
|
14
|
+
|
15
|
+
def visit_rec bb
|
16
|
+
print bb.label+":"
|
17
|
+
@visited << bb
|
18
|
+
@current=bb
|
19
|
+
bb.stmts.each do |stmt|
|
20
|
+
unless stmt.is_a? Break or stmt.is_a? Continue
|
21
|
+
puts "\t"+stmt.str.gsub(/;/,'')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
unless bb.stmts.last.is_a? Crokus::ITE
|
25
|
+
if bb.succs.any?
|
26
|
+
puts "\tgoto #{bb.succs.first.label}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
if bb.succs.empty?
|
30
|
+
puts "\tstop"
|
31
|
+
else
|
32
|
+
bb.succs.each do |bb|
|
33
|
+
unless @visited.include? bb
|
34
|
+
visit_rec(bb)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def visitITE ite,args=nil
|
41
|
+
cond=ite.cond.accept(self)
|
42
|
+
label1=ite.trueBranch.label
|
43
|
+
label2=ite.falseBranch.label
|
44
|
+
"\t"+"ite #{cond},#{label1},#{label2}"
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
data/lib/crokus/lexer.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
require_relative 'generic_lexer'
|
2
|
+
|
3
|
+
module Crokus
|
4
|
+
class Lexer < GenericLexer
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
super
|
8
|
+
ignore /\s+/
|
9
|
+
keyword "auto"
|
10
|
+
keyword "break"
|
11
|
+
keyword "case"
|
12
|
+
keyword "char"
|
13
|
+
keyword "const"
|
14
|
+
keyword "continue"
|
15
|
+
keyword "default"
|
16
|
+
keyword "do"
|
17
|
+
keyword "double"
|
18
|
+
keyword "else"
|
19
|
+
keyword "enum"
|
20
|
+
keyword "extern"
|
21
|
+
keyword "float"
|
22
|
+
keyword "for"
|
23
|
+
keyword "goto"
|
24
|
+
keyword "if"
|
25
|
+
keyword "int"
|
26
|
+
keyword "long"
|
27
|
+
keyword "register"
|
28
|
+
keyword "return"
|
29
|
+
keyword "short"
|
30
|
+
keyword "signed"
|
31
|
+
keyword "sizeof"
|
32
|
+
keyword "static"
|
33
|
+
keyword "struct"
|
34
|
+
keyword "switch"
|
35
|
+
keyword "typedef"
|
36
|
+
keyword "union"
|
37
|
+
keyword "unsigned"
|
38
|
+
keyword "void"
|
39
|
+
keyword "volatile"
|
40
|
+
keyword "while"
|
41
|
+
|
42
|
+
token :qmark => /\?/
|
43
|
+
token :lparen => /\(/
|
44
|
+
token :rparen => /\)/
|
45
|
+
token :lbrace => /\{/
|
46
|
+
token :rbrace => /\}/
|
47
|
+
token :lbrack => /\[/
|
48
|
+
token :rbrack => /\]/
|
49
|
+
token :semicolon => /;/
|
50
|
+
token :colon => /:/
|
51
|
+
token :comma => /\,/
|
52
|
+
token :lcomment => /\/\*/
|
53
|
+
token :rcomment => /\*\//
|
54
|
+
token :comment => /\/\/(.*)/
|
55
|
+
|
56
|
+
token :dot => /\./
|
57
|
+
token :neq => /!=/
|
58
|
+
token :not => /\!/
|
59
|
+
token :eq => /\=\=/
|
60
|
+
token :assign => /\=/
|
61
|
+
token :inc_op => /\+\+/
|
62
|
+
token :add_assign => /\+\=/
|
63
|
+
token :add => /\+/
|
64
|
+
token :dec_op => /\-\-/
|
65
|
+
token :sub_assign => /\-\=/
|
66
|
+
token :ptr_op => /\-\>/
|
67
|
+
token :sub => /\-/
|
68
|
+
token :mul_assign => /\*=/
|
69
|
+
token :mul => /\*/
|
70
|
+
token :div_assign => /\/=/
|
71
|
+
token :div => /\//
|
72
|
+
|
73
|
+
token :shift_r => /\>\>/
|
74
|
+
token :shift_l => /\<\</
|
75
|
+
token :oror => /\|\|/
|
76
|
+
token :lte => /<=/
|
77
|
+
token :lt => /</
|
78
|
+
token :gte => />=/
|
79
|
+
token :gt => />/
|
80
|
+
token :andand => /\&\&/
|
81
|
+
token :and => /\&/
|
82
|
+
token :or => /\|/
|
83
|
+
token :mod_assign => /\%=/
|
84
|
+
token :mod => /\%/
|
85
|
+
token :xor_assign => /\^\=/
|
86
|
+
token :xor => /\^/
|
87
|
+
|
88
|
+
token :sharp => /#/
|
89
|
+
|
90
|
+
# .............literals..............................
|
91
|
+
|
92
|
+
token :ident => /\A[a-zA-Z]\w*/i
|
93
|
+
token :float_lit => /\A\d*(\.\d+)(E([+-]?)\d+)?/
|
94
|
+
token :integer_lit => /\A(0x[0-9a-fA-F]+)|\d+/
|
95
|
+
token :string_lit => /\A"[^"]*"/
|
96
|
+
token :char_lit => /\A'\\?.'/
|
97
|
+
token :lexer_warning => /./
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
if $PROGRAM_NAME == __FILE__
|
104
|
+
str=IO.read(ARGV[0])
|
105
|
+
puts str
|
106
|
+
t1 = Time.now
|
107
|
+
lexer=Crokus::Lexer.new
|
108
|
+
tokens=lexer.tokenize(str)
|
109
|
+
t2 = Time.now
|
110
|
+
pp tokens
|
111
|
+
puts "number of tokens : #{tokens.size}"
|
112
|
+
puts "tokenized in : #{t2-t1} s"
|
113
|
+
end
|
@@ -0,0 +1,1072 @@
|
|
1
|
+
require 'pp'
|
2
|
+
|
3
|
+
require_relative 'lexer'
|
4
|
+
require_relative 'ast'
|
5
|
+
require_relative 'indent'
|
6
|
+
require_relative 'pretty_printer'
|
7
|
+
|
8
|
+
module Crokus
|
9
|
+
|
10
|
+
class Parser
|
11
|
+
|
12
|
+
attr_accessor :tokens,:str
|
13
|
+
include Indent
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@ppr=PrettyPrinter.new
|
17
|
+
@verbose=false
|
18
|
+
#@verbose=true
|
19
|
+
end
|
20
|
+
|
21
|
+
def acceptIt
|
22
|
+
say showNext.kind.to_s+" "+showNext.val
|
23
|
+
tokens.shift
|
24
|
+
end
|
25
|
+
|
26
|
+
def maybe kind
|
27
|
+
return acceptIt if showNext.is_a? kind
|
28
|
+
end
|
29
|
+
|
30
|
+
def expect kind
|
31
|
+
if ((actual=tokens.shift).kind)!=kind
|
32
|
+
puts "ERROR :"
|
33
|
+
show_line(actual.pos)
|
34
|
+
raise "expecting '#{kind}'. Received '#{actual.val}' around #{actual.pos}"
|
35
|
+
end
|
36
|
+
say actual.kind.to_s+" "+actual.val
|
37
|
+
return actual
|
38
|
+
end
|
39
|
+
|
40
|
+
def showNext(n=1)
|
41
|
+
tokens[n-1] if tokens.any?
|
42
|
+
end
|
43
|
+
|
44
|
+
def lookahead(n=2)
|
45
|
+
tokens[n] if tokens.any?
|
46
|
+
end
|
47
|
+
|
48
|
+
def show_line pos
|
49
|
+
l,c=*pos
|
50
|
+
show_lines(str,l-2)
|
51
|
+
line=str.split(/\n/)[l-1]
|
52
|
+
pointer="-"*(5+c)+ "^"
|
53
|
+
puts "#{l.to_s.ljust(5)}|#{line}"
|
54
|
+
puts pointer
|
55
|
+
end
|
56
|
+
#--------------------------------------------------
|
57
|
+
def dbg_print_next n
|
58
|
+
pp tokens[0..n-1].collect{|tok| tok.inspect}
|
59
|
+
end
|
60
|
+
|
61
|
+
def dbg_print node
|
62
|
+
puts "debug ast node".center(60,'-')
|
63
|
+
puts node.accept(@ppr)
|
64
|
+
puts "-"*60
|
65
|
+
end
|
66
|
+
#............ parsing methods ...........
|
67
|
+
def parse str
|
68
|
+
begin
|
69
|
+
@str=str
|
70
|
+
@tokens=Lexer.new.tokenize(str)
|
71
|
+
@tokens=remove_comments()
|
72
|
+
warnings=@tokens.select{|tok| tok.is_a? :lexer_warning}
|
73
|
+
show_lexer_warnings(warnings)
|
74
|
+
@tokens=@tokens.select{|tok| !tok.is_a? [:newline]}
|
75
|
+
ast=design_unit()
|
76
|
+
rescue Exception => e
|
77
|
+
puts "PARSING ERROR : #{e}"
|
78
|
+
puts "in C source at line/col #{showNext.pos}"
|
79
|
+
puts e.backtrace
|
80
|
+
abort
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def show_lexer_warnings warnings
|
85
|
+
warnings.each do |warn|
|
86
|
+
puts "lexer warning : #{warn.val} at #{warn.pos}"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def remove_comments
|
91
|
+
ret=[]
|
92
|
+
in_comment=false
|
93
|
+
tokens.each do |tok|
|
94
|
+
case tok.kind
|
95
|
+
when :comment
|
96
|
+
when :lcomment
|
97
|
+
in_comment=true
|
98
|
+
when :rcomment
|
99
|
+
in_comment=false
|
100
|
+
else
|
101
|
+
ret << tok unless in_comment
|
102
|
+
end
|
103
|
+
end
|
104
|
+
ret
|
105
|
+
end
|
106
|
+
|
107
|
+
def design_unit
|
108
|
+
indent "designUnit"
|
109
|
+
du=DesignUnit.new
|
110
|
+
while tokens.any?
|
111
|
+
case showNext.kind
|
112
|
+
when :sharp
|
113
|
+
case showNext(2).val
|
114
|
+
when "include"
|
115
|
+
du << include()
|
116
|
+
when "define"
|
117
|
+
du << define()
|
118
|
+
end
|
119
|
+
else
|
120
|
+
du << declaration
|
121
|
+
maybe :semicolon if tokens.any?
|
122
|
+
end
|
123
|
+
end
|
124
|
+
dedent
|
125
|
+
du.list.flatten!
|
126
|
+
return du
|
127
|
+
end
|
128
|
+
|
129
|
+
def include
|
130
|
+
indent "include"
|
131
|
+
expect :sharp
|
132
|
+
expect :ident #include
|
133
|
+
case showNext.kind
|
134
|
+
when :lt
|
135
|
+
acceptIt
|
136
|
+
id1=expect :ident
|
137
|
+
expect :dot
|
138
|
+
id2=expect :ident
|
139
|
+
expect :gt
|
140
|
+
name=Token.new [:ident,id1.val+"."+id2.val,id1.pos]
|
141
|
+
env=:env
|
142
|
+
when :string_lit
|
143
|
+
name=acceptIt
|
144
|
+
env=:local
|
145
|
+
end
|
146
|
+
dedent
|
147
|
+
return Include.new(name,env)
|
148
|
+
end
|
149
|
+
|
150
|
+
def define
|
151
|
+
indent "define"
|
152
|
+
expect :sharp
|
153
|
+
expect :ident #define
|
154
|
+
name=expect :ident
|
155
|
+
e=expression()
|
156
|
+
dedent
|
157
|
+
return Define.new(name,e)
|
158
|
+
end
|
159
|
+
|
160
|
+
def parse_struct
|
161
|
+
indent "struct"
|
162
|
+
expect :struct
|
163
|
+
name=nil
|
164
|
+
if showNext.is_a? :ident
|
165
|
+
name=acceptIt
|
166
|
+
end
|
167
|
+
ret=Struct.new(name)
|
168
|
+
if showNext.is_a? :lbrace
|
169
|
+
acceptIt
|
170
|
+
while !showNext.is_a? :rbrace
|
171
|
+
ret.decls << declaration()
|
172
|
+
end
|
173
|
+
ret.decls.flatten!
|
174
|
+
expect :rbrace
|
175
|
+
end
|
176
|
+
dedent
|
177
|
+
return ret
|
178
|
+
end
|
179
|
+
|
180
|
+
def typedef
|
181
|
+
indent "typedef"
|
182
|
+
expect :typedef
|
183
|
+
type=parse_type()
|
184
|
+
id=expect(:ident)
|
185
|
+
dedent
|
186
|
+
return Typedef.new(type,id)
|
187
|
+
end
|
188
|
+
|
189
|
+
def function_decl name,type_
|
190
|
+
indent "function"
|
191
|
+
args=function_formal_args()
|
192
|
+
case showNext.kind
|
193
|
+
when :semicolon
|
194
|
+
acceptIt
|
195
|
+
ret =FunctionProto.new(name,type_,args)
|
196
|
+
else
|
197
|
+
body=function_body()
|
198
|
+
ret= Function.new(name,type_,args,body)
|
199
|
+
end
|
200
|
+
dedent
|
201
|
+
return ret
|
202
|
+
end
|
203
|
+
|
204
|
+
def function_formal_args
|
205
|
+
indent "function_formal_args"
|
206
|
+
args=[]
|
207
|
+
expect :lparen
|
208
|
+
while !showNext.is_a? :rparen
|
209
|
+
args << func_formal_arg()
|
210
|
+
if !showNext.is_a? :rparen
|
211
|
+
expect :comma
|
212
|
+
end
|
213
|
+
end
|
214
|
+
expect :rparen
|
215
|
+
dedent
|
216
|
+
return args
|
217
|
+
end
|
218
|
+
|
219
|
+
def func_formal_arg
|
220
|
+
indent "function_arg"
|
221
|
+
@current_type=type=parse_type()
|
222
|
+
d=declarator
|
223
|
+
a=arrayed?(type)
|
224
|
+
#parenthesized?
|
225
|
+
dedent
|
226
|
+
return FormalArg.new(type,d)
|
227
|
+
end
|
228
|
+
|
229
|
+
def function_body
|
230
|
+
indent "function_body"
|
231
|
+
body=Body.new
|
232
|
+
expect :lbrace
|
233
|
+
while showNext.kind!=:rbrace
|
234
|
+
s=statement()
|
235
|
+
body << s if s
|
236
|
+
end
|
237
|
+
expect :rbrace
|
238
|
+
dedent
|
239
|
+
return body
|
240
|
+
end
|
241
|
+
|
242
|
+
def statement(arg=nil)
|
243
|
+
indent "statement ...#{showNext.kind} #{showNext.pos.first}"
|
244
|
+
case showNext.kind
|
245
|
+
when :lbrace
|
246
|
+
ret=parse_body()
|
247
|
+
when :unsigned,:signed,:int,:short,:float,:double,:long,:char,:void
|
248
|
+
ret=declaration()
|
249
|
+
when :struct
|
250
|
+
ret=declaration()
|
251
|
+
when :if
|
252
|
+
ret=parse_if()
|
253
|
+
when :while
|
254
|
+
ret=parse_while()
|
255
|
+
when :for
|
256
|
+
ret=parse_for()
|
257
|
+
when :switch
|
258
|
+
ret=switch()
|
259
|
+
when :return
|
260
|
+
ret=parse_return
|
261
|
+
when :break
|
262
|
+
acceptIt
|
263
|
+
ret=Break.new
|
264
|
+
when :continue
|
265
|
+
acceptIt
|
266
|
+
ret=Continue.new
|
267
|
+
when :do
|
268
|
+
ret=do_while()
|
269
|
+
when :goto
|
270
|
+
ret=parse_goto()
|
271
|
+
when :ident
|
272
|
+
case showNext(2).kind
|
273
|
+
when :ident
|
274
|
+
ret=declaration
|
275
|
+
when :colon
|
276
|
+
l=parse_label
|
277
|
+
s=statement
|
278
|
+
ret=LabeledStmt.new(l,s)
|
279
|
+
else
|
280
|
+
ret=expression_statement
|
281
|
+
end
|
282
|
+
when :const,:volatile
|
283
|
+
declaration
|
284
|
+
when :semicolon
|
285
|
+
acceptIt
|
286
|
+
#ret=expression_statement
|
287
|
+
when :inc_op,:dec_op
|
288
|
+
ret=expression_statement
|
289
|
+
else
|
290
|
+
show_line(showNext.pos)
|
291
|
+
raise "unknown statement start at #{showNext.pos} .Got #{showNext.kind} #{showNext.val}"
|
292
|
+
end
|
293
|
+
maybe :semicolon
|
294
|
+
dedent
|
295
|
+
return ret
|
296
|
+
end
|
297
|
+
|
298
|
+
def parse_label
|
299
|
+
expect :ident
|
300
|
+
expect :colon
|
301
|
+
end
|
302
|
+
|
303
|
+
def parse_goto
|
304
|
+
indent "goto"
|
305
|
+
expect :goto #label
|
306
|
+
id=expect(:ident)
|
307
|
+
dedent
|
308
|
+
Goto.new(id)
|
309
|
+
end
|
310
|
+
|
311
|
+
def do_while
|
312
|
+
indent "do_while"
|
313
|
+
expect :do
|
314
|
+
body=statement()
|
315
|
+
expect :while
|
316
|
+
e=expression
|
317
|
+
dedent
|
318
|
+
DoWhile.new(e,body)
|
319
|
+
end
|
320
|
+
|
321
|
+
def switch
|
322
|
+
indent "switch"
|
323
|
+
expect :switch
|
324
|
+
expect :lparen
|
325
|
+
e=expression
|
326
|
+
ret=Switch.new(e,cases=[],default=nil)
|
327
|
+
expect :rparen
|
328
|
+
expect :lbrace
|
329
|
+
while showNext.is_a? :case
|
330
|
+
expect :case
|
331
|
+
case_e=expression
|
332
|
+
case_body=Body.new
|
333
|
+
expect :colon
|
334
|
+
while showNext.kind!=:rbrace and showNext.kind!=:case and showNext.kind!=:default
|
335
|
+
case_body << statement()
|
336
|
+
end
|
337
|
+
cases << Case.new(case_e,case_body)
|
338
|
+
end
|
339
|
+
if showNext.is_a? :default
|
340
|
+
acceptIt
|
341
|
+
expect :colon
|
342
|
+
default_body=Body.new
|
343
|
+
while showNext.kind!=:rbrace
|
344
|
+
default_body << statement()
|
345
|
+
end
|
346
|
+
ret.default=default_body
|
347
|
+
end
|
348
|
+
expect :rbrace
|
349
|
+
dedent
|
350
|
+
return ret
|
351
|
+
end
|
352
|
+
|
353
|
+
def parse_return
|
354
|
+
indent "parse_return"
|
355
|
+
expect :return
|
356
|
+
unless showNext.is_a? :semicolon
|
357
|
+
e=expression
|
358
|
+
end
|
359
|
+
dedent
|
360
|
+
Return.new(e)
|
361
|
+
end
|
362
|
+
|
363
|
+
# int a
|
364
|
+
# int * a
|
365
|
+
# int a=1,b=2;
|
366
|
+
# int a[]
|
367
|
+
# int* f()
|
368
|
+
# struct name *ptr;
|
369
|
+
# paire_t paire = {1,2};
|
370
|
+
# int a,b[10],*c
|
371
|
+
#------------------------------
|
372
|
+
# TYPE ident
|
373
|
+
# ident ident
|
374
|
+
|
375
|
+
def declaration
|
376
|
+
ret=[]
|
377
|
+
@current_type=type=parse_type()
|
378
|
+
d=declarator()
|
379
|
+
a=arrayed?(type)
|
380
|
+
if a
|
381
|
+
type=a
|
382
|
+
end
|
383
|
+
func=parenthesized?
|
384
|
+
if func
|
385
|
+
func.type=type
|
386
|
+
ret << func #func
|
387
|
+
return ret
|
388
|
+
end
|
389
|
+
init=initialization?
|
390
|
+
ret << Decl.new(type,d,init)
|
391
|
+
while tokens.any? and showNext.is_a?(:comma)
|
392
|
+
acceptIt
|
393
|
+
ptr=pointed?
|
394
|
+
if ptr
|
395
|
+
type2=PointerTo.new(type)
|
396
|
+
end
|
397
|
+
d2=declarator
|
398
|
+
a2=arrayed?(type)
|
399
|
+
i2=initialization?
|
400
|
+
ret << Decl.new(type2||type,d2)
|
401
|
+
end
|
402
|
+
if tokens.any?
|
403
|
+
maybe :semicolon
|
404
|
+
end
|
405
|
+
return ret
|
406
|
+
end
|
407
|
+
|
408
|
+
def declarator
|
409
|
+
if showNext.is_a? :ident
|
410
|
+
ret=@current_ident=Ident.new(acceptIt)
|
411
|
+
end
|
412
|
+
return ret
|
413
|
+
end
|
414
|
+
|
415
|
+
def pointed?
|
416
|
+
return if tokens.empty?
|
417
|
+
while showNext.is_a? :mul
|
418
|
+
acceptIt
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
422
|
+
def arrayed?(type)
|
423
|
+
return if tokens.empty?
|
424
|
+
while showNext.is_a? :lbrack
|
425
|
+
acceptIt
|
426
|
+
if showNext.is_a? :rbrack
|
427
|
+
acceptIt
|
428
|
+
type=ArrayOf.new(type,IntLit.new(ZERO))
|
429
|
+
else
|
430
|
+
e=expression
|
431
|
+
type=ArrayOf.new(type,e)
|
432
|
+
expect :rbrack
|
433
|
+
end
|
434
|
+
end
|
435
|
+
return type
|
436
|
+
end
|
437
|
+
|
438
|
+
def initialization?
|
439
|
+
return if tokens.empty?
|
440
|
+
if showNext.is_a? :assign
|
441
|
+
expect :assign
|
442
|
+
e=expression
|
443
|
+
return e
|
444
|
+
end
|
445
|
+
end
|
446
|
+
|
447
|
+
def parenthesized?
|
448
|
+
return if tokens.empty?
|
449
|
+
if showNext.is_a? :lparen
|
450
|
+
f=function_decl(@current_ident,@current_type)
|
451
|
+
return f
|
452
|
+
end
|
453
|
+
end
|
454
|
+
|
455
|
+
def parse_type
|
456
|
+
indent "parse_type"
|
457
|
+
ret=Type.new(nil)
|
458
|
+
|
459
|
+
ret.precisions << spec_qualifier?() # const, volatile
|
460
|
+
if showNext.is_a? [:signed,:unsigned]
|
461
|
+
ret.precisions << acceptIt
|
462
|
+
end
|
463
|
+
|
464
|
+
case showNext.kind
|
465
|
+
when :ident,:char,:int,:short,:long,:float,:double,:void
|
466
|
+
ret.name=acceptIt
|
467
|
+
while showNext.is_a? [:char,:int,:short,:long,:float,:double,:void]
|
468
|
+
ret.precisions << ret.name
|
469
|
+
ret.name=acceptIt
|
470
|
+
end
|
471
|
+
ret.precisions.flatten!
|
472
|
+
when :struct
|
473
|
+
ret=parse_struct()
|
474
|
+
when :typedef
|
475
|
+
ret=typedef()
|
476
|
+
else
|
477
|
+
raise "Parsing ERROR in type declaration: '#{showNext}'"
|
478
|
+
end
|
479
|
+
|
480
|
+
while showNext.is_a? [:mul,:lparen]
|
481
|
+
case showNext.kind
|
482
|
+
when :mul
|
483
|
+
acceptIt
|
484
|
+
ret=PointerTo.new(ret)
|
485
|
+
when :lparen
|
486
|
+
acceptIt
|
487
|
+
if showNext.is_a? :rparen
|
488
|
+
acceptIt
|
489
|
+
else
|
490
|
+
expression
|
491
|
+
expect :rparen
|
492
|
+
end
|
493
|
+
end
|
494
|
+
end
|
495
|
+
dedent
|
496
|
+
return ret
|
497
|
+
end
|
498
|
+
|
499
|
+
def spec_qualifier?
|
500
|
+
list=[]
|
501
|
+
while showNext.is_a? STARTERS_TYPE_QUALIFIER
|
502
|
+
case showNext.kind
|
503
|
+
when :volatile
|
504
|
+
list << acceptIt
|
505
|
+
when :const
|
506
|
+
list << acceptIt
|
507
|
+
end
|
508
|
+
end
|
509
|
+
list
|
510
|
+
end
|
511
|
+
|
512
|
+
def parse_if
|
513
|
+
indent "parse_if"
|
514
|
+
expect :if
|
515
|
+
if showNext.is_a? :lparen # helps wrt casting.
|
516
|
+
acceptIt
|
517
|
+
lparen=true
|
518
|
+
end
|
519
|
+
cond=expression()
|
520
|
+
expect :rparen if lparen
|
521
|
+
body=Body.new
|
522
|
+
if showNext.is_a? :lbrace
|
523
|
+
lbrace=acceptIt
|
524
|
+
end
|
525
|
+
body << statement()
|
526
|
+
if lbrace
|
527
|
+
until showNext.is_a? :rbrace
|
528
|
+
body << statement
|
529
|
+
end
|
530
|
+
expect :rbrace
|
531
|
+
end
|
532
|
+
if showNext.is_a? :else
|
533
|
+
else_=parse_else()
|
534
|
+
end
|
535
|
+
dedent
|
536
|
+
return If.new(cond,body,else_)
|
537
|
+
end
|
538
|
+
|
539
|
+
def parse_else
|
540
|
+
indent "parse else"
|
541
|
+
expect :else
|
542
|
+
ret=Else.new
|
543
|
+
ret.body=statement()
|
544
|
+
dedent
|
545
|
+
return ret
|
546
|
+
end
|
547
|
+
|
548
|
+
def parse_while
|
549
|
+
indent "parse_while"
|
550
|
+
expect :while
|
551
|
+
cond=expression()
|
552
|
+
body=[]
|
553
|
+
body=statement()
|
554
|
+
dedent
|
555
|
+
return While.new(cond,body)
|
556
|
+
end
|
557
|
+
|
558
|
+
def parse_for
|
559
|
+
indent "parse_for"
|
560
|
+
forloop=For.new
|
561
|
+
expect :for
|
562
|
+
expect :lparen
|
563
|
+
forloop.init << expression_statement
|
564
|
+
forloop.cond = expression()
|
565
|
+
expect :semicolon
|
566
|
+
forloop.increment=expression()
|
567
|
+
expect :rparen
|
568
|
+
forloop.body=statement()
|
569
|
+
dedent
|
570
|
+
forloop
|
571
|
+
end
|
572
|
+
|
573
|
+
def parseLoopInit
|
574
|
+
indent "parseLoopInit"
|
575
|
+
ret=statement()
|
576
|
+
dedent
|
577
|
+
return [ret] # because for (int a,b=0;i<10;i++) is also possible.
|
578
|
+
# then parser returns an array of Decl
|
579
|
+
end
|
580
|
+
|
581
|
+
def parseLoopCond
|
582
|
+
indent "parseLoopCond"
|
583
|
+
e=expression()
|
584
|
+
dedent
|
585
|
+
return e
|
586
|
+
end
|
587
|
+
|
588
|
+
def parseLoopEnd
|
589
|
+
indent "parseLoopEnd"
|
590
|
+
s=statement()
|
591
|
+
dedent
|
592
|
+
return s
|
593
|
+
end
|
594
|
+
|
595
|
+
def parse_body
|
596
|
+
body=Body.new
|
597
|
+
expect :lbrace
|
598
|
+
while !showNext.is_a? :rbrace
|
599
|
+
body << statement()
|
600
|
+
end
|
601
|
+
expect :rbrace
|
602
|
+
return body
|
603
|
+
end
|
604
|
+
|
605
|
+
def expression_statement
|
606
|
+
if showNext.is_a? :semicolon
|
607
|
+
acceptIt
|
608
|
+
else
|
609
|
+
e=expression
|
610
|
+
expect :semicolon
|
611
|
+
return e
|
612
|
+
end
|
613
|
+
end
|
614
|
+
#===============================================================
|
615
|
+
def debug
|
616
|
+
puts " "*@indentation+@tokens[0..4].map{|t| "'#{t.val}'"}.join(" ")
|
617
|
+
end
|
618
|
+
#===============================================================
|
619
|
+
def expression
|
620
|
+
indent "expression : #{showNext}"
|
621
|
+
e1=assign()
|
622
|
+
while showNext.is_a? :comma
|
623
|
+
acceptIt
|
624
|
+
e2=assign()
|
625
|
+
e1=CommaStmt.new(e1,e2)
|
626
|
+
end
|
627
|
+
dedent
|
628
|
+
return e1
|
629
|
+
end
|
630
|
+
|
631
|
+
STARTERS_ARRAY_OR_STRUCT_INIT=[:lbrace]
|
632
|
+
STARTERS_PRIMARY=[:ident,:integer_lit,:float_lit,:string_lit,:char_lit,:lparen]+STARTERS_ARRAY_OR_STRUCT_INIT
|
633
|
+
UNARY_OP=[:and,:mul,:add,:sub,:tilde,:not]
|
634
|
+
STARTERS_UNARY=[:inc_op,:dec_op,:sizeof]+STARTERS_PRIMARY+UNARY_OP
|
635
|
+
ASSIGN_OP=[:assign,:add_assign,:sub_assign,:mul_assign,:div_assign,:mod_assign,:xor_assign]
|
636
|
+
|
637
|
+
def assign
|
638
|
+
indent "assign : #{showNext}"
|
639
|
+
e1=cond_expr
|
640
|
+
while showNext.is_a? ASSIGN_OP
|
641
|
+
op=acceptIt
|
642
|
+
e2=assign
|
643
|
+
e1=Assign.new(e1,op,e2)
|
644
|
+
end
|
645
|
+
dedent
|
646
|
+
return e1
|
647
|
+
end
|
648
|
+
|
649
|
+
def cond_expr
|
650
|
+
indent "cond_expr : #{showNext}"
|
651
|
+
e1=logor
|
652
|
+
while showNext.is_a? :qmark
|
653
|
+
acceptIt
|
654
|
+
e2=expression
|
655
|
+
expect :colon
|
656
|
+
e3=cond_expr
|
657
|
+
e1=CondExpr.new(e1,e2,e3)
|
658
|
+
end
|
659
|
+
dedent
|
660
|
+
return e1
|
661
|
+
end
|
662
|
+
|
663
|
+
def logor
|
664
|
+
indent "logor : #{showNext}"
|
665
|
+
e1=logand
|
666
|
+
while showNext.is_a? :oror
|
667
|
+
op=acceptIt
|
668
|
+
e2=logand
|
669
|
+
e1=Or2.new(e1,op,e2)
|
670
|
+
end
|
671
|
+
dedent
|
672
|
+
return e1
|
673
|
+
end
|
674
|
+
|
675
|
+
def logand
|
676
|
+
indent "logand : #{showNext}"
|
677
|
+
e1=inclor
|
678
|
+
while showNext.is_a? :andand
|
679
|
+
op=acceptIt
|
680
|
+
e2=inclor
|
681
|
+
e1=Binary.new(e1,op,e2)
|
682
|
+
end
|
683
|
+
dedent
|
684
|
+
e1
|
685
|
+
end
|
686
|
+
|
687
|
+
def inclor
|
688
|
+
indent "inclor : #{showNext}"
|
689
|
+
e1=exclor
|
690
|
+
while showNext.is_a? :or
|
691
|
+
op=acceptIt
|
692
|
+
e2=exclor
|
693
|
+
e1=Binary.new(e1,op,e2)
|
694
|
+
end
|
695
|
+
dedent
|
696
|
+
e1
|
697
|
+
end
|
698
|
+
|
699
|
+
def exclor
|
700
|
+
indent "exclor : #{showNext}"
|
701
|
+
e1=andexp
|
702
|
+
while showNext.is_a? :xor
|
703
|
+
op=acceptIt
|
704
|
+
e2=andexp
|
705
|
+
e1=Binary.new(e1,op,e2)
|
706
|
+
end
|
707
|
+
dedent
|
708
|
+
e1
|
709
|
+
end
|
710
|
+
|
711
|
+
def andexp
|
712
|
+
indent "andexp : #{showNext}"
|
713
|
+
e1=eqexp
|
714
|
+
while showNext.is_a? :and
|
715
|
+
op=acceptIt
|
716
|
+
e2=eqexp
|
717
|
+
e1=Binary.new(e1,op,e2)
|
718
|
+
end
|
719
|
+
dedent
|
720
|
+
e1
|
721
|
+
end
|
722
|
+
|
723
|
+
def eqexp
|
724
|
+
indent "eqexp : #{showNext}"
|
725
|
+
e1=relexp
|
726
|
+
while showNext.is_a? [:eq,:neq]
|
727
|
+
op=acceptIt
|
728
|
+
e2=relexp
|
729
|
+
e1=Binary.new(e1,op,e2)
|
730
|
+
end
|
731
|
+
dedent
|
732
|
+
e1
|
733
|
+
end
|
734
|
+
|
735
|
+
def relexp
|
736
|
+
indent "relexp : #{showNext}"
|
737
|
+
e1=shiftexp
|
738
|
+
while showNext.is_a? [:lte,:lt,:gte,:gt ]
|
739
|
+
op=acceptIt
|
740
|
+
e2=shiftexp
|
741
|
+
e1=Binary.new(e1,op,e2)
|
742
|
+
end
|
743
|
+
dedent
|
744
|
+
e1
|
745
|
+
end
|
746
|
+
|
747
|
+
def shiftexp
|
748
|
+
indent "shiftexp : #{showNext}"
|
749
|
+
e1=additive
|
750
|
+
while showNext.is_a? [:shift_l,:shift_r]
|
751
|
+
op=acceptIt
|
752
|
+
e2=additive
|
753
|
+
e1=Binary.new(e1,op,e2)
|
754
|
+
end
|
755
|
+
dedent
|
756
|
+
e1
|
757
|
+
end
|
758
|
+
|
759
|
+
def additive
|
760
|
+
indent "addititve : #{showNext}"
|
761
|
+
e1=multitive
|
762
|
+
while showNext.is_a? [:add,:sub]
|
763
|
+
op=acceptIt
|
764
|
+
e2=multitive
|
765
|
+
e1=Binary.new(e1,op,e2)
|
766
|
+
end
|
767
|
+
dedent
|
768
|
+
e1
|
769
|
+
end
|
770
|
+
|
771
|
+
def multitive
|
772
|
+
indent "multitive : #{showNext}"
|
773
|
+
e1=castexp
|
774
|
+
while showNext.is_a? [:mul,:div,:mod]
|
775
|
+
op=acceptIt
|
776
|
+
e2=castexp
|
777
|
+
e1=Binary.new(e1,op,e2)
|
778
|
+
end
|
779
|
+
dedent
|
780
|
+
e1
|
781
|
+
end
|
782
|
+
|
783
|
+
def castexp
|
784
|
+
indent "castexpr : #{showNext}"
|
785
|
+
case showNext.kind
|
786
|
+
when :lparen # parenth expr OR casting !
|
787
|
+
res=is_casting?
|
788
|
+
puts "casting? : #{res}" if $options[:verbose]
|
789
|
+
if res
|
790
|
+
e=casting
|
791
|
+
else
|
792
|
+
e=parenthesized
|
793
|
+
end
|
794
|
+
else
|
795
|
+
e=unary
|
796
|
+
end
|
797
|
+
dedent
|
798
|
+
return e
|
799
|
+
end
|
800
|
+
|
801
|
+
def is_casting?
|
802
|
+
i=0
|
803
|
+
tok=DUMMY
|
804
|
+
while tok.kind!=:rparen
|
805
|
+
tok=@tokens[i]
|
806
|
+
i+=1
|
807
|
+
end
|
808
|
+
tok=@tokens[i]
|
809
|
+
return false if tok.is_a? [:mul,:add,:sub]
|
810
|
+
return true if tok.is_a? STARTERS_UNARY-STARTERS_ARRAY_OR_STRUCT_INIT
|
811
|
+
return false
|
812
|
+
end
|
813
|
+
|
814
|
+
def casting
|
815
|
+
puts "casting : #{showNext}" if $options[:verbose]
|
816
|
+
expect :lparen
|
817
|
+
#typename
|
818
|
+
t=parse_type
|
819
|
+
expect :rparen
|
820
|
+
u=unary
|
821
|
+
CastedExpr.new(t,u)
|
822
|
+
end
|
823
|
+
|
824
|
+
def parenthesized
|
825
|
+
indent "parenthesized : #{showNext}"
|
826
|
+
expect :lparen
|
827
|
+
e=expression
|
828
|
+
expect :rparen
|
829
|
+
dedent
|
830
|
+
return Parenth.new(e)
|
831
|
+
end
|
832
|
+
|
833
|
+
def typename
|
834
|
+
indent "typename"
|
835
|
+
type=specifier_qualifier
|
836
|
+
while showNext.is_a? STARTERS_ABSTRACT_DECLARATOR
|
837
|
+
list << abstract_decl
|
838
|
+
end
|
839
|
+
dedent
|
840
|
+
list
|
841
|
+
end
|
842
|
+
|
843
|
+
def spec_qualifier_list
|
844
|
+
indent "spec_qualifier_list #{showNext.inspect}"
|
845
|
+
while showNext.is_a? STARTERS_TYPE_SPECIFIER+STARTERS_TYPE_QUALIFIER
|
846
|
+
if showNext.is_a? STARTERS_TYPE_SPECIFIER
|
847
|
+
list << type_specifier
|
848
|
+
else
|
849
|
+
list << type_qualifier
|
850
|
+
end
|
851
|
+
end
|
852
|
+
dedent
|
853
|
+
list
|
854
|
+
end
|
855
|
+
|
856
|
+
STARTERS_TYPE_SPECIFIER=[:void,:char,:short,:int,:long,:float,:signed,:unsigned,:struct,:union,:enum,:ident]
|
857
|
+
def type_specifier
|
858
|
+
type=Type.new(nil,[])
|
859
|
+
indent "type_specifier #{showNext}"
|
860
|
+
if showNext.is_a? STARTERS_TYPE_SPECIFIER
|
861
|
+
ret=acceptIt
|
862
|
+
type.name=ret
|
863
|
+
else
|
864
|
+
raise "ERROR : type_specifier. Expecting one of '#{STARTERS_TYPE_SPECIFIER}' at #{showNext.pos}"
|
865
|
+
end
|
866
|
+
dedent
|
867
|
+
type
|
868
|
+
end
|
869
|
+
|
870
|
+
# abstract_declarator
|
871
|
+
# : pointer
|
872
|
+
# | direct_abstract_declarator
|
873
|
+
# | pointer direct_abstract_declarator
|
874
|
+
# ;
|
875
|
+
STARTERS_ABSTRACT_DECLARATOR=[:mul,:lparen,:lbrack]
|
876
|
+
def abstract_decl
|
877
|
+
indent "abstract_decl"
|
878
|
+
if showNext.is_a? STARTERS_ABSTRACT_DECLARATOR
|
879
|
+
case showNext.kind
|
880
|
+
when :mul
|
881
|
+
pointer
|
882
|
+
else
|
883
|
+
direct_abstract_declarator
|
884
|
+
end
|
885
|
+
else
|
886
|
+
raise "ERROR : in abstract_declarator. Expecting one of #{STARTERS_ABSTRACT_DECLARATOR}"
|
887
|
+
end
|
888
|
+
dedent
|
889
|
+
end
|
890
|
+
|
891
|
+
# pointer
|
892
|
+
# : '*'
|
893
|
+
# | '*' type_qualifier_list
|
894
|
+
# | '*' pointer
|
895
|
+
# | '*' type_qualifier_list pointer
|
896
|
+
# ;
|
897
|
+
STARTERS_TYPE_QUALIFIER=[:const,:volatile]
|
898
|
+
def pointer
|
899
|
+
expect :mul
|
900
|
+
while showNext.is_a? STARTERS_TYPE_QUALIFIER+[:mul]
|
901
|
+
case showNext.kind
|
902
|
+
when :volatile
|
903
|
+
acceptIt
|
904
|
+
when :const
|
905
|
+
acceptIt
|
906
|
+
when :mult
|
907
|
+
acceptIt
|
908
|
+
end
|
909
|
+
end
|
910
|
+
end
|
911
|
+
|
912
|
+
def direct_abstract_declarator
|
913
|
+
raise
|
914
|
+
end
|
915
|
+
|
916
|
+
def unary
|
917
|
+
if STARTERS_PRIMARY.include? showNext.kind
|
918
|
+
u=postfix
|
919
|
+
elsif showNext.is_a? [:and,:mul,:add,:sub,:tilde,:not]
|
920
|
+
op=acceptIt
|
921
|
+
e=castexp
|
922
|
+
u=Unary.new(op,e)
|
923
|
+
else
|
924
|
+
case showNext.kind
|
925
|
+
when :inc_op
|
926
|
+
op=acceptIt
|
927
|
+
u=unary
|
928
|
+
u=PreFixAccu.new(op,u)
|
929
|
+
when :dec_op
|
930
|
+
op=acceptIt
|
931
|
+
u=unary
|
932
|
+
u=PreFixAccu.new(op,u)
|
933
|
+
when :sizeof
|
934
|
+
u=sizeof()
|
935
|
+
else
|
936
|
+
raise "not an unary"
|
937
|
+
end
|
938
|
+
end
|
939
|
+
return u
|
940
|
+
end
|
941
|
+
|
942
|
+
def sizeof
|
943
|
+
expect :sizeof
|
944
|
+
case showNext.kind
|
945
|
+
when :lparen
|
946
|
+
acceptIt
|
947
|
+
#e=typename
|
948
|
+
e=parse_type
|
949
|
+
expect :rparen
|
950
|
+
else
|
951
|
+
#e=unary
|
952
|
+
e=expression
|
953
|
+
end
|
954
|
+
Sizeof.new(e)
|
955
|
+
end
|
956
|
+
|
957
|
+
def postfix
|
958
|
+
indent "postfix : #{showNext}"
|
959
|
+
e1=primary
|
960
|
+
while showNext.is_a? [:lbrack,:lparen,:dot,:inc_op,:dec_op,:ptr_op]
|
961
|
+
case showNext.kind
|
962
|
+
when :lbrack
|
963
|
+
acceptIt
|
964
|
+
e2=expression
|
965
|
+
expect :rbrack
|
966
|
+
e1=Indexed.new(e1,e2)
|
967
|
+
when :lparen
|
968
|
+
acceptIt
|
969
|
+
args=[]
|
970
|
+
if !showNext.is_a? :rparen
|
971
|
+
args=argument_expr_list
|
972
|
+
end
|
973
|
+
expect :rparen
|
974
|
+
args=linearize_comma_stmt(args)
|
975
|
+
e1=FunCall.new(e1,args)
|
976
|
+
when :dot
|
977
|
+
acceptIt
|
978
|
+
e2=Ident.new(expect :ident)
|
979
|
+
e1=Dotted.new(e1,e2)
|
980
|
+
when :ptr_op
|
981
|
+
op=acceptIt
|
982
|
+
expect :ident
|
983
|
+
when :inc_op,:dec_op
|
984
|
+
op=acceptIt
|
985
|
+
e1=PostFixAccu.new(e1,op)
|
986
|
+
end
|
987
|
+
end
|
988
|
+
dedent
|
989
|
+
e1
|
990
|
+
end
|
991
|
+
|
992
|
+
def linearize_comma_stmt ary
|
993
|
+
ary.collect do |stmt|
|
994
|
+
case stmt
|
995
|
+
when CommaStmt
|
996
|
+
stmt.to_list
|
997
|
+
else
|
998
|
+
stmt
|
999
|
+
end
|
1000
|
+
end.flatten
|
1001
|
+
end
|
1002
|
+
|
1003
|
+
def primary
|
1004
|
+
case showNext.kind
|
1005
|
+
when :ident
|
1006
|
+
return Ident.new(acceptIt)
|
1007
|
+
when :integer_lit
|
1008
|
+
return IntLit.new(acceptIt)
|
1009
|
+
when :float_lit
|
1010
|
+
return FloatLit.new(acceptIt)
|
1011
|
+
when :string_lit
|
1012
|
+
return StrLit.new(acceptIt)
|
1013
|
+
when :char_lit
|
1014
|
+
return CharLit.new(acceptIt)
|
1015
|
+
when :lparen
|
1016
|
+
acceptIt
|
1017
|
+
e=expression
|
1018
|
+
expect :rparen
|
1019
|
+
return Parenth.new(e)
|
1020
|
+
when :lbrace
|
1021
|
+
return array_or_struct_init()
|
1022
|
+
end
|
1023
|
+
end
|
1024
|
+
|
1025
|
+
def argument_expr_list
|
1026
|
+
list=[]
|
1027
|
+
list << expression
|
1028
|
+
while showNext.is_a? :comma
|
1029
|
+
acceptIt
|
1030
|
+
list << expression
|
1031
|
+
end
|
1032
|
+
list
|
1033
|
+
end
|
1034
|
+
|
1035
|
+
def array_or_struct_init
|
1036
|
+
indent "array_or_struct_init"
|
1037
|
+
expect :lbrace
|
1038
|
+
elements=[]
|
1039
|
+
while !showNext.is_a? :rbrace
|
1040
|
+
elements << (e=expression)
|
1041
|
+
if showNext.is_a? :comma
|
1042
|
+
acceptIt
|
1043
|
+
end
|
1044
|
+
end
|
1045
|
+
expect :rbrace
|
1046
|
+
dedent
|
1047
|
+
return ArrayOrStructInit.new(elements)
|
1048
|
+
end
|
1049
|
+
|
1050
|
+
end#class Parser
|
1051
|
+
end #module
|
1052
|
+
|
1053
|
+
def show_lines str,upto=nil
|
1054
|
+
lines=str.split(/\n/)
|
1055
|
+
upto=upto || lines.size
|
1056
|
+
lines[0..upto].each_with_index do |line,idx|
|
1057
|
+
puts "#{(idx+1).to_s.ljust(5)}|#{line}"
|
1058
|
+
end
|
1059
|
+
end
|
1060
|
+
|
1061
|
+
if $PROGRAM_NAME == __FILE__
|
1062
|
+
require_relative 'dot_printer_rec'
|
1063
|
+
str=IO.read(ARGV[0])
|
1064
|
+
show_lines(str)
|
1065
|
+
t1 = Time.now
|
1066
|
+
parser=C::Parser.new
|
1067
|
+
ast=parser.parse(str)
|
1068
|
+
dot=C::DotPrinter.new.print(ast)
|
1069
|
+
dot.save_as "test.dot"
|
1070
|
+
t2 = Time.now
|
1071
|
+
puts "parsed in : #{t2-t1} s"
|
1072
|
+
end
|