/vqdr/trunk

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/vqdr/trunk

« back to all changes in this revision

Viewing changes to src/libvqdr/parser.vala

  • Committer: Gustav Hartvigsson
  • Date: 2022-06-01 12:14:52 UTC
  • Revision ID: gustav.hartvigsson@gmail.com-20220601121452-ntu94w67q3dhhfeq
More work torwards inperementing the parser.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
using VQDR.Expression;
2
 
 
3
 
namespace VQDR {
4
 
  public errordomain ParserError {
5
 
    NOT_READY,
6
 
    INVALID_DATA;
7
 
  }
8
 
 
9
 
  enum CharType {
10
 
    NULL = 0,
 
1
using Utils;
 
2
 
 
3
namespace VQDR.Expression {
 
4
 
 
5
  public enum CharType {
 
6
    INVALID = 0,
 
7
    NULL = 1,
11
8
    DIGIT,
12
9
    UOP,
13
10
    OP,
16
13
    POP,
17
14
    PCL,
18
15
    COM,
19
 
    UNKNOWN;
20
 
   
21
 
   
 
16
    UNKNOWN,
 
17
    _NUM_VAL;
 
18
 
 
19
    public string to_string () {
 
20
      // We add one as we have an invalid case.
 
21
      static_assert (CharType._NUM_VAL == 10 + 1);
 
22
      switch (this) {
 
23
        case (NULL): 
 
24
          return "NULL";
 
25
        case (DIGIT):
 
26
          return "DIGIT";
 
27
        case (UOP):
 
28
          return "UOP";
 
29
        case (OP):
 
30
          return "OP";
 
31
        case (ALPHA):
 
32
          return "ALPHA";
 
33
        case (DOT):
 
34
          return "DOT";
 
35
        case (POP):
 
36
          return "POP";
 
37
        case (PCL):
 
38
          return "PLC";
 
39
        case (COM):
 
40
          return "COM";
 
41
        case (UNKNOWN):
 
42
          return "UNKNOWN";
 
43
        default:
 
44
          assert_not_reached ();
 
45
      }
 
46
    }
 
47
 
22
48
  /**
23
49
   * Determine character type.
24
50
   * @param ch Character to be checked.
25
51
   * @return The character type.
26
52
   */
27
 
    CharType from_char (char ch) {
 
53
    public static CharType from_char (char ch) {
28
54
      switch (ch) {
29
55
        case '0': case '1':
30
56
        case '2': case '3':
50
76
          if ((ch >= 'a' && ch <= 'z') || (ch>= 'A' && ch <= 'Z' )) {
51
77
            return ALPHA;
52
78
          }
53
 
        assert_not_reached ();
54
 
      }
55
 
    }
56
 
  }
57
 
 
58
 
  public string parser_error_to_string (ParserError e) {
59
 
    switch (e.code) {
60
 
      case (ParserError.NOT_READY):
61
 
        return "NOT READY";
62
 
      case (ParserError.INVALID_DATA):
63
 
        return "INVALID_DATA";
64
 
      default:
65
 
        assert_not_reached ();
66
 
    }
67
 
  }
68
 
 
69
 
  class Parser {
70
 
    private class Lexer {
71
 
      private bool ready = false;
72
 
      private string? data = null;
73
 
      private size_t data_size = 0;
74
 
      private Array<Token> tokens = null;
75
 
      private char cur_char = 0;
76
 
      private int index = -1;
77
 
 
78
 
      public Lexer (string data) {
79
 
        assert (data.length != 0);
80
 
        this.data = data;
81
 
        this.data_size = data.length;
82
 
        this.cur_char = data[0];
83
 
        this.index = 0;
84
 
        tokens = new Array<Token> ();
85
 
 
86
 
      }
87
 
 
88
 
      public void lex () throws ParserError {
89
 
        while (this.index <= this.data_size) {
90
 
          
91
 
        }
92
 
        this.ready = true;
93
 
      }
94
 
 
95
 
      private void advance () {
96
 
        if (this.index < this.data_size && this.cur_char != '\0') {
97
 
          this.index++;
98
 
          this.cur_char = this.data[this.index];
99
 
        } else {
100
 
          assert_not_reached ();
101
 
        }
102
 
      }
103
 
      
104
 
 
105
 
      public Array<Token>? get_tokens () throws ParserError {
106
 
        if (!ready) {
107
 
          throw (new ParserError.NOT_READY ("Lexer is not ready." +
108
 
                                            "Needs to run Lexer.lex() first."));
109
 
        }
110
 
 
111
 
        return tokens;
112
 
      }
113
 
    }
114
 
  }
 
79
          return UNKNOWN;
 
80
      }
 
81
    }
 
82
  }
 
83
 
 
84
  public class Parser {
 
85
    private static string[] EMPTY_VAR_KEYS = new string[0];
 
86
    private Context context = null;
 
87
    /** Contains the used variable names. */
 
88
    private string[] variable_keys;
 
89
    /** contains the used variables and their last value. */
 
90
    private HashTable<string, Variable?> variable_cache; 
 
91
    /** Will contain the Root of the token tree.
 
92
     * Asumes that there it has no parents.*/
 
93
    private Token root_token;
 
94
    private Token root;
 
95
    private bool parsed = false;
 
96
    private bool evaluated_once;
 
97
    private string internal_experisson;
 
98
    public string expression {
 
99
      get {return internal_experisson;}
 
100
      set {internal_experisson = value;
 
101
           expression_size = value.length;
 
102
           reset ();}
 
103
    }
 
104
    private size_t expression_size = 0;
 
105
    private char cur_char = 0;
 
106
    private int index = -1;
 
107
 
 
108
    private FastNumber result_value;
 
109
    private FastNumber result_max_value;
 
110
    private FastNumber result_min_value;
 
111
 
 
112
    private string result_string;
 
113
    private Error? error;
 
114
 
 
115
 
 
116
    public Parser (string expression) {
 
117
      this.expression = expression;
 
118
      this.expression_size = expression.length;
 
119
      this.cur_char = expression[0];
 
120
      this.index = 0;
 
121
    }
 
122
 
 
123
    public Parser.empty () {
 
124
      expression = "";
 
125
    }
 
126
 
 
127
    public void reset () {
 
128
      root_token = null;
 
129
      root = null;
 
130
      parsed = false;
 
131
      evaluated_once = false;
 
132
      result_value = FastNumber (0);
 
133
      result_min_value = FastNumber (0);
 
134
      result_max_value = FastNumber (0);
 
135
      result_string = "";
 
136
      variable_cache.remove_all ();
 
137
      variable_keys = EMPTY_VAR_KEYS;
 
138
      error = null;
 
139
      index = 0;
 
140
    }
 
141
 
 
142
    /**
 
143
     * Parse the expersson string.
 
144
     */
 
145
    public void parse () throws ParseError {
 
146
      if (parsed) {
 
147
        throw new ParseError.ALLREADY_PARSED 
 
148
              ("Data has allparsed been parsed.");
 
149
      }
 
150
 
 
151
 
 
152
      while (this.index <= this.expression_size) {
 
153
        switch (CharType.from_char (this.cur_char)) {
 
154
          case CharType.NULL:
 
155
            this.parse_advance ();
 
156
            break;
 
157
          default:
 
158
            assert_not_reached ();
 
159
        }
 
160
      }
 
161
      this.parsed = true;
 
162
    } // end parse ()
 
163
 
 
164
    /*
 
165
     * advance the parser. 
 
166
     */
 
167
    private void parse_advance () {
 
168
      if (this.index < this.expression_size && this.cur_char != '\0') {
 
169
        this.index++;
 
170
        this.cur_char = this.expression[this.index];
 
171
      }
 
172
    }
 
173
 
 
174
    protected bool valid_bounds () {
 
175
      if (!evaluated_once) {
 
176
        return false;
 
177
      }
 
178
 
 
179
      if (context != null) {
 
180
        try {
 
181
          foreach (var key in variable_keys) {
 
182
            if (!context.has_name (key) ||
 
183
                !variable_cache.get (key).equals (context.get_variable (key))) {
 
184
              return false;
 
185
            }
 
186
          }
 
187
        } catch (Error e) {
 
188
          err_print_ln ("Something went wrong: (%: %)", e.domain, e.message);
 
189
          assert_not_reached ();
 
190
        }
 
191
      }
 
192
      return true;
 
193
    }
 
194
 
 
195
    protected void set_variable_cach_values () {
 
196
      if (context != null) {
 
197
        try {
 
198
          foreach (var key in variable_keys) {
 
199
            variable_cache.insert (key, Variable.copy (context.get_variable (key)));
 
200
          }
 
201
        } catch (Error e) {
 
202
          err_print_ln ("Something went wrong: (%: %)", e.domain, e.message);
 
203
          assert_not_reached ();
 
204
        }
 
205
      }
 
206
    }
 
207
 
 
208
    protected void set_error (Error e) {
 
209
      expression = "";
 
210
 
 
211
      result_string = "Error";
 
212
 
 
213
      set_variable_cach_values ();
 
214
 
 
215
      error = e;
 
216
    }
 
217
 
 
218
    protected void set_result (Token root_token) {
 
219
      // evaluate = true;
 
220
      evaluated_once = true;
 
221
 
 
222
      result_value = root_token.result_value;
 
223
      result_max_value = root_token.result_max_value;
 
224
      result_min_value = root_token.result_min_value;
 
225
      result_string = root_token.result_string;
 
226
 
 
227
      set_variable_cach_values ();
 
228
 
 
229
      error = null;
 
230
    }
 
231
 
 
232
    protected void evaluate () throws Error {
 
233
      try {
 
234
        parse ();
 
235
 
 
236
        if (root_token == null) {
 
237
          root_token = new RootToken (root);
 
238
        }
 
239
 
 
240
        root_token.evaluate (context);
 
241
 
 
242
        set_result (root_token);
 
243
      } catch (Error e) {
 
244
        set_error (e);
 
245
        throw e;
 
246
      }
 
247
    }
 
248
 
 
249
    /**
 
250
     * Add a note (operator) to the stack after popping it's parameters.
 
251
     * @param operand_stack stack
 
252
     * @param operator operator.
 
253
     */
 
254
    protected void add_node (Stack<Token> operand_stack, Token operator) throws Error {
 
255
      if (operator is FunctionToken) {
 
256
        FunctionToken funk = (FunctionToken) operator;
 
257
        int param_num = funk.next_child_num;
 
258
        for (var i = 0; i < param_num; i++) {
 
259
          Token param_child = operand_stack.pop ();
 
260
          funk.set_child (param_num - 1, param_child);
 
261
 
 
262
          operand_stack.push (funk);
 
263
        }
 
264
      } else if (operator is UnaryOperator && ((UnaryOperator) operator).is_unary) {
 
265
        if (operand_stack.elements < 1) {
 
266
          throw new OperandError.MISSING_OPERAND (@"Missing operand. Position: $(operator.position)");
 
267
        }
 
268
      } else {
 
269
        if (operand_stack.elements < 2) {
 
270
          throw new OperandError.MISSING_OPERAND (@"Missing operand. Position: $(operator.position)");
 
271
        }
 
272
        operator.set_right_child (operand_stack.pop ());
 
273
        operator.set_left_child (operand_stack.pop ());
 
274
        operand_stack.push (operator);
 
275
      }
 
276
    }
 
277
  } // end of Parser class
115
278
}