File: parser.rb

package info (click to toggle)
jgrep 1.5.4-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, forky, sid, trixie
  • size: 184 kB
  • sloc: ruby: 1,004; makefile: 8
file content (116 lines) | stat: -rw-r--r-- 4,013 bytes parent folder | download
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
module JGrep
  class Parser
    attr_reader :scanner, :execution_stack

    def initialize(args)
      @scanner = Scanner.new(args)
      @execution_stack = []

      parse
    end

    # Parse the input string, one token at a time a contruct the call stack
    def parse(substatement = nil, token_index = 0)
      p_token = nil

      if substatement
        c_token, c_token_value = substatement[token_index]
      else
        c_token, c_token_value = @scanner.get_token
      end

      parenth = 0

      until c_token.nil?
        if substatement
          token_index += 1
          n_token, n_token_value = substatement[token_index]
        else
          @scanner.token_index += 1
          n_token, n_token_value = @scanner.get_token
        end

        next if n_token == " "
        case c_token

        when "and"
          unless (n_token =~ /not|statement|\(|\+|-/) || (scanner.token_index == scanner.arguments.size)
            raise "Error at column #{scanner.token_index}. \nExpected 'not', 'statement' or '('. Found '#{n_token_value}'"
          end

          raise "Error at column #{scanner.token_index}. \n Expression cannot start with 'and'" if p_token.nil?
          raise "Error at column #{scanner.token_index}. \n #{p_token} cannot be followed by 'and'" if %w[and or].include?(p_token)

        when "or"
          unless (n_token =~ /not|statement|\(|\+|-/) || (scanner.token_index == scanner.arguments.size)
            raise "Error at column #{scanner.token_index}. \nExpected 'not', 'statement', '('. Found '#{n_token_value}'"
          end

          raise "Error at column #{scanner.token_index}. \n Expression cannot start with 'or'" if p_token.nil?
          raise "Error at column #{scanner.token_index}. \n #{p_token} cannot be followed by 'or'" if %w[and or].include?(p_token)

        when "not"
          unless n_token =~ /statement|\(|not|\+|-/
            raise "Error at column #{scanner.token_index}. \nExpected 'statement' or '('. Found '#{n_token_value}'"
          end

        when "statement"
          if c_token_value.is_a? Array
            raise "Error at column #{scanner.token_index}\nError, cannot define '[' in a '[...]' block." if substatement

            parse(c_token_value, 0)
          end

          if c_token_value.is_a?(String) && c_token_value =~ /!=/
            c_token_value = c_token_value.gsub("!=", "=")
            @execution_stack << {"not" => "not"}
          end

          if !n_token.nil? && !n_token.match(/and|or|\)/)
            raise "Error at column #{scanner.token_index}. \nExpected 'and', 'or', ')'. Found '#{n_token_value}'"
          end

        when "+"
          if !n_token.nil? && !n_token.match(/and|or|\)/)
            raise "Error at column #{scanner.token_index}. \nExpected 'and', 'or', ')'. Found '#{n_token_value}'"
          end

        when "-"
          if !n_token.nil? && !n_token.match(/and|or|\)/)
            raise "Error at column #{scanner.token_index}. \nExpected 'and', 'or', ')'. Found '#{n_token_value}'"
          end

        when ")"
          if !n_token.nil? && n_token !~ /|and|or|not|\(/
            raise "Error at column #{scanner.token_index}. \nExpected 'and', 'or', 'not' or '('. Found '#{n_token_value}'"
          end

          parenth += 1

        when "("
          unless n_token =~ /statement|not|\(|\+|-/
            raise "Error at column #{scanner.token_index}. \nExpected 'statement', '(',  not. Found '#{n_token_value}'"
          end

          parenth -= 1

        else
          raise "Unexpected token found at column #{scanner.token_index}. '#{c_token_value}'"
        end

        unless n_token == " " || substatement
          @execution_stack << {c_token => c_token_value}
        end

        p_token = c_token
        c_token = n_token
        c_token_value = n_token_value
      end

      return if substatement

      raise "Error. Missing parentheses ')'." if parenth < 0
      raise "Error. Missing parentheses '('." if parenth > 0
    end
  end
end