/
ebnf
executable file
·91 lines (80 loc) · 3.27 KB
/
ebnf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#!/usr/bin/env ruby
# ebnf --- Process EBNF to generate the following:
# * S-Expression
# * Turtle
# * Either of the above, transformed to BNF
# * And with First/Follow rules
$:.unshift(File.expand_path(File.join(File.dirname(__FILE__), "..", 'lib')))
require "bundler/setup"
require 'rubygems'
require 'getoptlong'
require 'ebnf'
options = {
:output_format => :sxp,
:prefix => "ttl",
:namespace => "http://www.w3.org/ns/formats/Turtle#",
}
input, out = nil, STDOUT
OPT_ARGS = [
["--debug", GetoptLong::NO_ARGUMENT, "Turn on debugging output"],
["--bnf", GetoptLong::NO_ARGUMENT, "Transform EBNF to BNF"],
["--evaluate","-e", GetoptLong::REQUIRED_ARGUMENT,"Evaluate argument as an EBNF document"],
["--ll1", GetoptLong::REQUIRED_ARGUMENT,"Generate First/Follow rules, argument is start symbol"],
["--format", "-f", GetoptLong::REQUIRED_ARGUMENT,"Specify output format one of ebnf, html, ttl, sxp, or rb"],
["--input-format", GetoptLong::REQUIRED_ARGUMENT,"Specify input format one of ebnf or sxp"],
["--mod-name", GetoptLong::REQUIRED_ARGUMENT,"Module name used when creating ruby tables"],
["--output", "-o", GetoptLong::REQUIRED_ARGUMENT,"Output to the specified file path"],
["--prefix", "-p", GetoptLong::REQUIRED_ARGUMENT,"Prefix to use when generating Turtle"],
["--progress", "-v", GetoptLong::NO_ARGUMENT, "Detail on execution"],
["--namespace", "-n", GetoptLong::REQUIRED_ARGUMENT,"Namespace to use when generating Turtle"],
["--help", "-?", GetoptLong::NO_ARGUMENT, "This message"]
]
def usage
STDERR.puts %{#{$0} Version #{EBNF::VERSION}}
STDERR.puts %{Usage: #{$0} [options] file ...}
width = OPT_ARGS.map do |o|
l = o.first.length
l += o[1].length + 2 if o[1].is_a?(String)
l
end.max
OPT_ARGS.each do |o|
s = " %-*s " % [width, (o[1].is_a?(String) ? "#{o[0,2].join(', ')}" : o[0])]
s += o.last
STDERR.puts s
end
exit(1)
end
opts = GetoptLong.new(*OPT_ARGS.map {|o| o[0..-2]})
opts.each do |opt, arg|
case opt
when '--debug' then options[:debug] = true
when '--bnf' then options[:bnf] = true
when '--evaluate' then input = arg
when '--input-format' then options[:format] = arg.to_sym
when '--format' then options[:output_format] = arg.to_sym
when '--ll1' then (options[:ll1] ||= []) <<arg.to_sym
when '--mod-name' then options[:mod_name] = arg
when '--output' then out = File.open(arg, "w")
when '--prefix' then options[:prefix] = arg
when '--namespace' then options[:namespace] = arg
when '--progress' then options[:progress] = true
when '--help' then usage
end
end
if options[:output_format] == :rb && !options[:ll1]
STDERR.puts "outputing in .rb format requires -ll"
exit(1)
end
input = File.open(ARGV[0]) if ARGV[0]
ebnf = EBNF.parse(input || STDIN, options)
ebnf.make_bnf if options[:bnf] || options[:ll1]
ebnf.first_follow(*options[:ll1]) if options[:ll1]
res = case options[:output_format]
when :ebnf then ebnf.to_s
when :html then ebnf.to_html
when :sxp then ebnf.to_sxp
when :ttl then ebnf.to_ttl(options[:prefix], options[:namespace])
when :rb then ebnf.to_ruby(out, options.merge(grammarFile: ARGV[0]))
else ebnf.ast.inspect
end
out.puts res