summaryrefslogtreecommitdiff
path: root/ext/ripper/tools/preproc.rb
blob: a92be93d5b976f9fd4060e0beb62a3e5ec3cda64 (plain)
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# frozen_string_literal: true
# $Id$

require 'optparse'

def main
  output = nil
  template = nil
  parser = OptionParser.new
  parser.banner = "Usage: #{File.basename($0)} [--output=PATH] [--template=PATH] <parse.y>"
  parser.on('--output=PATH', 'An output file.') {|path|
    output = path
  }
  parser.on('--template=PATH', 'An template file.') {|path|
    template = path
  }
  parser.on('--help', 'Prints this message and quit.') {
    puts parser.help
    exit true
  }
  begin
    parser.parse!
  rescue OptionParser::ParseError => err
    warn err.message
    abort parser.help
  end
  out = "".dup
  if ARGV[0] == "-"
    unless ARGV.size == 2
      abort "wrong number of arguments (#{ARGV.size} for 2)"
    end
    process STDIN, out, ARGV[1], template
  else
    unless ARGV.size == 1
      abort "wrong number of arguments (#{ARGV.size} for 1)"
    end
    File.open(ARGV[0]) {|f|
      process f, out, ARGV[0], template
    }
  end
  if output
    File.write(output, out)
  else
    print out
  end
end

def process(f, out, path, template)
  prelude f, out
  grammar f, out
  usercode f, out, path, template
end

require_relative 'dsl'

def generate_line(f, out)
  while line = f.gets
    case
    when gen = DSL.line?(line)
      out << gen.generate << "\n"
    when line.start_with?("%%")
      out << "%%\n"
      break
    else
      out << yield(line)
    end
  end
end

def prelude(f, out)
  @exprs = {}
  generate_line(f, out) do |line|
    if (/^enum lex_state_(?:bits|e) \{/ =~ line)..(/^\}/ =~ line)
      case line
      when /^\s*(EXPR_\w+),\s+\/\*(.+)\*\//
        @exprs[$1.chomp("_bit")] = $2.strip
      when /^\s*(EXPR_\w+)\s+=\s+(.+)$/
        name = $1
        val = $2.chomp(",")
        @exprs[name] = "equals to " + (val.start_with?("(") ? "<tt>#{val}</tt>" : "+#{val}+")
      end
    end
    line
  end
end

def grammar(f, out)
  generate_line(f, out) do |line|
    case line
    when %r</\*%%%\*/>
      "#if 0\n"
    when %r</\*%>
      "#endif\n"
    when %r<%\*/>
      "\n"
    else
      line
    end
  end
end

def usercode(f, out, path, template)
  require 'erb'
  lineno = nil
  src = nil
  compiler = ERB::Compiler.new('%-')
  compiler.put_cmd = compiler.insert_cmd = "out.<<"

  if template
    File.open(template) do |f|
      out.clear
      lineno = f.lineno
      src, = compiler.compile(f.read)
      path = template
    end
  else
    lineno = f.lineno
    src, = compiler.compile(f.read)
  end

  eval(src, binding, path, lineno)
end

main