scrag 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/scrag +4 -0
- data/lib/scrag/code.rb +47 -0
- data/lib/scrag/compiler.rb +119 -0
- data/lib/scrag/runner.rb +71 -0
- data/lib/scrag/version.rb +3 -0
- data/lib/scrag.rb +6 -0
- data/lib/templates/ast.erb +42 -0
- data/lib/templates/code.erb +47 -0
- data/lib/templates/compiler.erb +28 -0
- data/lib/templates/exec.erb +4 -0
- data/lib/templates/gemspec.erb +33 -0
- data/lib/templates/generic_lexer.erb +62 -0
- data/lib/templates/generic_parser.erb +53 -0
- data/lib/templates/lexer.erb +50 -0
- data/lib/templates/parser.erb +73 -0
- data/lib/templates/pretty_printer.erb +29 -0
- data/lib/templates/runner.erb +97 -0
- data/lib/templates/token.erb +63 -0
- data/lib/templates/top_module.erb +7 -0
- data/lib/templates/transformer.erb +487 -0
- data/lib/templates/version.erb +3 -0
- data/lib/templates/visitor.erb +39 -0
- metadata +79 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6497b445e4a0f1279357da48c6f451ad76e7969c7c565c857d11b89405668c90
|
4
|
+
data.tar.gz: 3f8d6c011473b47341a1b6392327bf3cc92768639fac176ee563b38d73910398
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f6e779ad79c007d369bfe72b3505072ebc8e33ba49d228d1a898575721ede6598a983c81335e673188fc009f49ce64aba10cb5a76ea5f59226ef82daa6e080f0
|
7
|
+
data.tar.gz: a0b5c131b51aff35b7c03f785733e2c244073c0cfa375e3ebc030cc3e55096e210f67e56465b8b741e1c83cd26392af1edfce4614cbf6299110f9fd70c15f064
|
data/bin/scrag
ADDED
data/lib/scrag/code.rb
ADDED
@@ -0,0 +1,47 @@
|
|
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
|
+
puts "=> code saved as : #{filename}" if verbose
|
39
|
+
return filename
|
40
|
+
end
|
41
|
+
|
42
|
+
def size
|
43
|
+
@lines.size
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require_relative 'code'
|
3
|
+
|
4
|
+
module Scrag
|
5
|
+
|
6
|
+
class Compiler
|
7
|
+
|
8
|
+
attr_accessor :options
|
9
|
+
attr_accessor :project_name
|
10
|
+
|
11
|
+
def initialize options={}
|
12
|
+
@options=options
|
13
|
+
end
|
14
|
+
|
15
|
+
def compile project_name
|
16
|
+
@project_name=project_name.downcase
|
17
|
+
puts "project #{project_name}".center(65,'=')
|
18
|
+
@files_for_dir={
|
19
|
+
project_name => [:gemspec],
|
20
|
+
"bin" => [:exec],
|
21
|
+
"lib" => [:top_module],
|
22
|
+
"lib/#{project_name}" => [
|
23
|
+
:ast,
|
24
|
+
:code,
|
25
|
+
:compiler,
|
26
|
+
:exec,
|
27
|
+
:generic_lexer,
|
28
|
+
:generic_parser,
|
29
|
+
:lexer,
|
30
|
+
:parser,
|
31
|
+
:pretty_printer,
|
32
|
+
:runner,
|
33
|
+
:token,
|
34
|
+
:top_module,
|
35
|
+
:transformer,
|
36
|
+
:version,
|
37
|
+
:visitor,
|
38
|
+
]
|
39
|
+
}
|
40
|
+
generate
|
41
|
+
end
|
42
|
+
|
43
|
+
def item n=0,str
|
44
|
+
subitem=(n==0) ? "": " "
|
45
|
+
spaces=case n
|
46
|
+
when 0 then 0
|
47
|
+
when 1 then 1
|
48
|
+
else
|
49
|
+
1+(n-1)*4
|
50
|
+
end
|
51
|
+
|
52
|
+
puts " "*spaces+"#{subitem}[+] #{str}"
|
53
|
+
end
|
54
|
+
|
55
|
+
def generate
|
56
|
+
@pwd=Dir.pwd
|
57
|
+
check_doesnt_exists(project_name)
|
58
|
+
create "#{project_name}"
|
59
|
+
create "#{project_name}/bin"
|
60
|
+
create "#{project_name}/lib"
|
61
|
+
create "#{project_name}/lib/#{project_name}"
|
62
|
+
create "#{project_name}/tests"
|
63
|
+
end
|
64
|
+
|
65
|
+
def create dir
|
66
|
+
item "creating dir '#{dir}'"
|
67
|
+
create_stuff dir
|
68
|
+
end
|
69
|
+
|
70
|
+
def check_doesnt_exists dir
|
71
|
+
if Dir.exists?(dir)
|
72
|
+
if options[:force]
|
73
|
+
puts "WARNING : project already exists !"
|
74
|
+
puts "Are you sure you want to force generation ? files will be lost !"
|
75
|
+
key=$stdin.chomp
|
76
|
+
puts key
|
77
|
+
else
|
78
|
+
puts "Scrag ERROR : project '#{project_name}' already exists. Type -v for options."
|
79
|
+
abort
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def create_stuff dir
|
85
|
+
Dir.mkdir dir
|
86
|
+
Dir.chdir dir
|
87
|
+
rel_dir=dir.split('/')[1..-1].join('/')
|
88
|
+
files_to_create=@files_for_dir[rel_dir]
|
89
|
+
if files_to_create
|
90
|
+
files_to_create.each do |file|
|
91
|
+
create_file(file)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
Dir.chdir @pwd
|
95
|
+
end
|
96
|
+
|
97
|
+
SPECIALS=[:top_module,:exec,:gemspec]
|
98
|
+
def create_file file
|
99
|
+
|
100
|
+
gen_file=(SPECIALS.include?(file)) ? project_name : file
|
101
|
+
ext=case file
|
102
|
+
when :exec then ""
|
103
|
+
when :gemspec then ".gemspec"
|
104
|
+
else ".rb"
|
105
|
+
end
|
106
|
+
item 1,"creating file '#{gen_file}'"
|
107
|
+
template=load_template(file)
|
108
|
+
renderer=ERB.new(template)
|
109
|
+
gen_code=renderer.result(binding)
|
110
|
+
code=Code.new(gen_code)
|
111
|
+
code.save_as "#{gen_file}#{ext}",verbose=false
|
112
|
+
end
|
113
|
+
|
114
|
+
def load_template file
|
115
|
+
template="#{__dir__}/../templates/#{file}.erb"
|
116
|
+
template_str=IO.read template
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
data/lib/scrag/runner.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require "optparse"
|
2
|
+
require "colorize"
|
3
|
+
|
4
|
+
require_relative "compiler"
|
5
|
+
|
6
|
+
module Scrag
|
7
|
+
|
8
|
+
class Runner
|
9
|
+
|
10
|
+
def self.run *arguments
|
11
|
+
new.run(arguments)
|
12
|
+
end
|
13
|
+
|
14
|
+
def run arguments
|
15
|
+
compiler=Compiler.new
|
16
|
+
compiler.options = options = parse_options(arguments)
|
17
|
+
if project=options[:project_name]
|
18
|
+
compiler.compile project
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def header
|
23
|
+
puts "Scrag : scaffolding Ruby compilers (#{VERSION})- (c) JC Le Lann 20"
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def parse_options(arguments)
|
28
|
+
header
|
29
|
+
|
30
|
+
parser = OptionParser.new
|
31
|
+
|
32
|
+
options = {}
|
33
|
+
|
34
|
+
parser.on("-h", "--help", "Show help message") do
|
35
|
+
puts parser
|
36
|
+
print_help_message
|
37
|
+
exit(true)
|
38
|
+
end
|
39
|
+
|
40
|
+
parser.on("--vv", "verbose") do
|
41
|
+
options[:verbose] = true
|
42
|
+
end
|
43
|
+
|
44
|
+
parser.on("--force", "force creation, even if file structure already exists") do
|
45
|
+
options[:force] = true
|
46
|
+
end
|
47
|
+
|
48
|
+
parser.on("-v", "--version", "Show version number") do
|
49
|
+
puts VERSION
|
50
|
+
exit(true)
|
51
|
+
end
|
52
|
+
|
53
|
+
parser.parse!(arguments)
|
54
|
+
|
55
|
+
options[:project_name]=arguments.shift #the remaining c file
|
56
|
+
|
57
|
+
unless options[:project_name]
|
58
|
+
puts parser
|
59
|
+
print_help_message
|
60
|
+
end
|
61
|
+
|
62
|
+
options
|
63
|
+
end
|
64
|
+
|
65
|
+
def print_help_message
|
66
|
+
puts
|
67
|
+
puts "simply enter your project name like > scrag my_dsl".green
|
68
|
+
puts
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/lib/scrag.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# your project process may use rkgen for class generation :
|
2
|
+
# require_relative "ast_<%=project_name%>_rkgen"
|
3
|
+
|
4
|
+
module <%=project_name.capitalize%>
|
5
|
+
|
6
|
+
class AstNode
|
7
|
+
def accept(visitor, arg=nil)
|
8
|
+
name = self.class.name.split(/::/).last
|
9
|
+
visitor.send("visit#{name}".to_sym, self ,arg) # Metaprograming !
|
10
|
+
end
|
11
|
+
|
12
|
+
def str
|
13
|
+
ppr=PrettyPrinter.new
|
14
|
+
self.accept(ppr)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class Root < AstNode
|
19
|
+
attr_accessor :design_units
|
20
|
+
def initialize design_units=[]
|
21
|
+
@design_units=design_units
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Ident < AstNode
|
26
|
+
attr_accessor :token
|
27
|
+
def initialize token=nil
|
28
|
+
@token=token
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class Expression
|
33
|
+
end
|
34
|
+
|
35
|
+
class Binary < Expression
|
36
|
+
attr_accessor :lhs,:op,:rhs
|
37
|
+
def initialize lhs=nil,op=nil,rhs=nil
|
38
|
+
@lhs,@op,@rhs=lhs,op,rhs
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,47 @@
|
|
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
|
+
puts "=> code saved as : #{filename}" if verbose
|
39
|
+
return filename
|
40
|
+
end
|
41
|
+
|
42
|
+
def size
|
43
|
+
@lines.size
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require_relative 'parser'
|
3
|
+
require_relative 'pretty_printer'
|
4
|
+
require_relative 'transformer'
|
5
|
+
require_relative 'code'
|
6
|
+
|
7
|
+
module <%=project_name.capitalize%>
|
8
|
+
|
9
|
+
class Compiler
|
10
|
+
|
11
|
+
attr_accessor :options
|
12
|
+
attr_accessor :project_name
|
13
|
+
|
14
|
+
def initialize options={}
|
15
|
+
@options=options
|
16
|
+
end
|
17
|
+
|
18
|
+
def compile filename
|
19
|
+
puts "=> compiling #{filename}"
|
20
|
+
# parse(filename)
|
21
|
+
end
|
22
|
+
|
23
|
+
def parse filename
|
24
|
+
@ast=Parser.new.parse filename
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require_relative "./lib/<%=project_name%>/version"
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = '<%=project_name%>'
|
5
|
+
s.version = <%project_name.capitalize%>::VERSION
|
6
|
+
s.date = Time.now.strftime("%Y-%m-%d")
|
7
|
+
s.summary = "<%= project_name%> DSL compiler"
|
8
|
+
s.description = "<%= project_name%> DSL compiler"
|
9
|
+
s.authors = ["Jean-Christophe Le Lann"]
|
10
|
+
s.email = 'lelannje@ensta-bretagne.fr'
|
11
|
+
s.files = [
|
12
|
+
"lib/<%=project_name%>/runner.rb",
|
13
|
+
"lib/<%=project_name%>/compiler.rb",
|
14
|
+
"lib/<%=project_name%>/ast.rb",
|
15
|
+
"lib/<%=project_name%>/code.rb",
|
16
|
+
"lib/<%=project_name%>/generic_lexer.rb",
|
17
|
+
"lib/<%=project_name%>/generic_parser.rb",
|
18
|
+
"lib/<%=project_name%>/lexer.rb",
|
19
|
+
"lib/<%=project_name%>/parser.rb",
|
20
|
+
"lib/<%=project_name%>/pretty_printer.rb",
|
21
|
+
"lib/<%=project_name%>/token.rb",
|
22
|
+
"lib/<%=project_name%>/version.rb",
|
23
|
+
"lib/<%=project_name%>.rb"
|
24
|
+
]
|
25
|
+
|
26
|
+
s.executables << '<%=project_name%>'
|
27
|
+
s.homepage = 'https://github.com/JC-LL/<%=project_name%>'
|
28
|
+
s.license = 'MIT'
|
29
|
+
s.post_install_message = "Thanks for installing ! Homepage :https://github.com/JC-LL/<%=project_name%>"
|
30
|
+
s.required_ruby_version = '>= 2.0.0'
|
31
|
+
s.add_runtime_dependency 'colorize', '0.8.1'
|
32
|
+
|
33
|
+
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/i]
|
18
|
+
end
|
19
|
+
|
20
|
+
def token hash
|
21
|
+
token,pattern=*hash.to_a.flatten
|
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(5)}'... "
|
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 #usefull for debug
|
60
|
+
tokens
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
class GenericParser
|
2
|
+
|
3
|
+
def acceptIt
|
4
|
+
tok=tokens.shift
|
5
|
+
puts "consuming #{tok.val} (#{tok.kind})" if @verbose
|
6
|
+
tok
|
7
|
+
end
|
8
|
+
|
9
|
+
def showNext k=1
|
10
|
+
tokens[k-1]
|
11
|
+
end
|
12
|
+
|
13
|
+
def expect kind
|
14
|
+
if (actual=showNext.kind)!=kind
|
15
|
+
abort "ERROR at #{showNext.pos}. Expecting #{kind}. Got #{actual}"
|
16
|
+
else
|
17
|
+
return acceptIt()
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def maybe kind
|
22
|
+
if showNext.kind==kind
|
23
|
+
return acceptIt
|
24
|
+
end
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
28
|
+
def more?
|
29
|
+
!tokens.empty?
|
30
|
+
end
|
31
|
+
|
32
|
+
def lookahead n
|
33
|
+
showNext(k=n)
|
34
|
+
end
|
35
|
+
|
36
|
+
def niy
|
37
|
+
raise "NIY"
|
38
|
+
end
|
39
|
+
|
40
|
+
def next_tokens n=5
|
41
|
+
@tokens[0..n].map{|tok| [tok.kind,tok.val].to_s}.join(',')
|
42
|
+
end
|
43
|
+
|
44
|
+
def consume_to token_kind
|
45
|
+
while showNext && showNext.kind!=token_kind
|
46
|
+
acceptIt
|
47
|
+
end
|
48
|
+
if showNext.nil?
|
49
|
+
raise "cannot find token '#{token_kind}'"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require_relative 'generic_lexer'
|
2
|
+
require_relative 'generic_parser'
|
3
|
+
|
4
|
+
module <%=project_name.capitalize%>
|
5
|
+
class Lexer < GenericLexer
|
6
|
+
def initialize
|
7
|
+
super
|
8
|
+
|
9
|
+
keyword 'if'
|
10
|
+
|
11
|
+
#.............................................................
|
12
|
+
token :comment => /\A\-\-(.*)$/
|
13
|
+
token :ident => /[a-zA-Z]\w*/
|
14
|
+
token :string_literal => /"[^"]*"/
|
15
|
+
token :char_literal => /'(\w+)'/
|
16
|
+
token :decimal_literal => /\d+(\.\d+)?(E([+-]?)\d+)?/
|
17
|
+
|
18
|
+
token :comma => /\A\,/
|
19
|
+
token :colon => /\A\:/
|
20
|
+
token :semicolon => /\A\;/
|
21
|
+
token :lparen => /\A\(/
|
22
|
+
token :rparen => /\A\)/
|
23
|
+
|
24
|
+
# arith
|
25
|
+
token :add => /\A\+/
|
26
|
+
token :sub => /\A\-/
|
27
|
+
token :mul => /\A\*/
|
28
|
+
token :div => /\A\//
|
29
|
+
|
30
|
+
token :imply => /\A\=\>/
|
31
|
+
|
32
|
+
# logical
|
33
|
+
token :eq => /\A\=/
|
34
|
+
token :neq => /\A\/\=/
|
35
|
+
token :gte => /\A\>\=/
|
36
|
+
token :gt => /\A\>/
|
37
|
+
token :leq => /\A\<\=/
|
38
|
+
token :lt => /\A\</
|
39
|
+
|
40
|
+
token :ampersand => /\A\&/
|
41
|
+
|
42
|
+
token :dot => /\A\./
|
43
|
+
token :bar => /\|/
|
44
|
+
#............................................................
|
45
|
+
token :newline => /[\n]/
|
46
|
+
token :space => /[ \t\r]+/
|
47
|
+
|
48
|
+
end #def
|
49
|
+
end #class
|
50
|
+
end #module
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require_relative 'generic_parser'
|
3
|
+
require_relative 'ast'
|
4
|
+
require_relative 'lexer'
|
5
|
+
|
6
|
+
module <%=project_name.capitalize%>
|
7
|
+
|
8
|
+
class Parser < GenericParser
|
9
|
+
|
10
|
+
attr_accessor :options
|
11
|
+
attr_accessor :lexer,:tokens
|
12
|
+
attr_accessor :basename,:filename
|
13
|
+
|
14
|
+
def initialize options={}
|
15
|
+
@options=options
|
16
|
+
end
|
17
|
+
|
18
|
+
def lex filename
|
19
|
+
unless File.exists?(filename)
|
20
|
+
raise "ERROR : cannot find file '#{filename}'"
|
21
|
+
end
|
22
|
+
begin
|
23
|
+
str=IO.read(filename).downcase
|
24
|
+
tokens=Lexer.new.tokenize(str)
|
25
|
+
tokens=tokens.select{|t| t.class==Token} # filters [nil,nil,nil]
|
26
|
+
tokens.reject!{|tok| tok.is_a? [:comment,:newline,:space]}
|
27
|
+
return tokens
|
28
|
+
rescue Exception=>e
|
29
|
+
unless options[:mute]
|
30
|
+
puts e.backtrace
|
31
|
+
puts e
|
32
|
+
end
|
33
|
+
raise "an error occured during LEXICAL analysis. Sorry. Aborting."
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def parse filename
|
38
|
+
begin
|
39
|
+
@tokens=lex(filename)
|
40
|
+
puts "......empty file !" if tokens.size==0
|
41
|
+
root=Root.new([])
|
42
|
+
while @tokens.any?
|
43
|
+
case showNext.kind
|
44
|
+
when :comment
|
45
|
+
root << acceptIt
|
46
|
+
# etc...
|
47
|
+
else
|
48
|
+
raise "got #{showNext}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
rescue Exception => e
|
52
|
+
unless options[:mute]
|
53
|
+
puts e.backtrace
|
54
|
+
puts e
|
55
|
+
end
|
56
|
+
raise
|
57
|
+
end
|
58
|
+
root
|
59
|
+
end
|
60
|
+
|
61
|
+
def parse_thing
|
62
|
+
expect :thing
|
63
|
+
expect :ident
|
64
|
+
while showNext.is_a?(:comma)
|
65
|
+
acceptIt
|
66
|
+
expect :ident
|
67
|
+
end
|
68
|
+
expect :semicolon
|
69
|
+
end
|
70
|
+
|
71
|
+
# ....etc...
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative 'code'
|
2
|
+
|
3
|
+
module <%=project_name.capitalize%>
|
4
|
+
|
5
|
+
class PrettyPrinter
|
6
|
+
|
7
|
+
def print ast
|
8
|
+
ast.accept(self)
|
9
|
+
end
|
10
|
+
|
11
|
+
def visitRoot root,args=nil
|
12
|
+
code=Code.new
|
13
|
+
code << "--automatically generated"
|
14
|
+
root.list.each{|e| code << e.accept(self)}
|
15
|
+
code
|
16
|
+
end
|
17
|
+
|
18
|
+
def visitComment comment,args=nil
|
19
|
+
code=Code.new
|
20
|
+
comment.list.each{|e| code << e.accept(self)}
|
21
|
+
code
|
22
|
+
end
|
23
|
+
|
24
|
+
def visitIdent id,args=nil
|
25
|
+
id.token.val
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|