spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← Commit log
commit
message
[ParseEngine] work-in-progress, creating new parser engine starting with actions, rules, rectioons, and symbols
author
Ben Vogt <[email protected]>
date
2017-12-07 02:58:18
stats
3 file(s) changed, 740 insertions(+), 18 deletions(-)
files
src/Parser/ObjectBuilder.ts
src/Parser/ParseEngine.ts
src/Parser/ParserConstants.ts
  1diff --git a/src/Parser/ObjectBuilder.ts b/src/Parser/ObjectBuilder.ts
  2new file mode 100644
  3index 0000000..6dd3917
  4--- /dev/null
  5+++ b/src/Parser/ObjectBuilder.ts
  6@@ -0,0 +1,24 @@
  7+/**
  8+ * Utility class to help build objects programmatically. Basically this allows me to have source code where constants
  9+ * are keys in objects.
 10+ */
 11+class ObjectBuilder {
 12+  public o : Object = {};
 13+
 14+  public static add(k, v) : ObjectBuilder {
 15+    let m = new ObjectBuilder();
 16+    m.o[k.toString()] = v;
 17+    return m;
 18+  }
 19+  public add(k, v) : ObjectBuilder {
 20+    this.o[k.toString()] = v;
 21+    return this;
 22+  }
 23+  public build() : Object {
 24+    return this.o;
 25+  }
 26+}
 27+
 28+export {
 29+  ObjectBuilder
 30+}
 31\ No newline at end of file
 32diff --git a/src/Parser/ParseEngine.ts b/src/Parser/ParseEngine.ts
 33new file mode 100644
 34index 0000000..c10b62d
 35--- /dev/null
 36+++ b/src/Parser/ParseEngine.ts
 37@@ -0,0 +1,712 @@
 38+import {
 39+  ObjectBuilder
 40+} from "./ObjectBuilder";
 41+
 42+// Rules represent the Regular Expressions that will be used in sequence to match a given input to the Parser.
 43+const Rules = {
 44+  WHITE_SPACE : /^(?:\s+)/,
 45+  DOUBLE_QUOTES : /^(?:"(\\["]|[^"])*")/,
 46+  SINGLE_QUOTES : /^(?:'(\\[']|[^'])*')/,
 47+  FORMULA_NAME : /^(?:[A-Za-z.]{1,}[A-Za-z_0-9]+(?=[(]))/,
 48+  $_A1_CELL : /^(?:\$[A-Za-z]+\$[0-9]+)/,
 49+  A1_CELL : /^(?:[A-Za-z]+[0-9]+)/,
 50+  FORMULA_NAME_SIMPLE : /^(?:[A-Za-z.]+(?=[(]))/,
 51+  VARIABLE : /^(?:[A-Za-z]{1,}[A-Za-z_0-9]+)/,
 52+  SIMPLE_VARIABLE : /^(?:[A-Za-z_]+)/,
 53+  INTEGER : /^(?:[0-9]+(?:(?:[eE])(?:[\+-])?[0-9]+)?)/,
 54+  OPEN_ARRAY:  /^(?:\[)/,
 55+  CLOSE_ARRAY:  /^(?:\])/,
 56+  DOLLAR_SIGN : /^(?:\$)/,
 57+  AMPERSAND_SIGN : /^(?:&)/,
 58+  SINGLE_WHITESPACE : /^(?: )/,
 59+  PERIOD : /^(?:[.])/,
 60+  COLON : /^(?::)/,
 61+  SEMI_COLON : /^(?:;)/,
 62+  COMMA : /^(?:,)/,
 63+  ASTERISK : /^(?:\*)/,
 64+  FORWARD_SLASH : /^(?:\/)/,
 65+  MINUS_SIGN : /^(?:-)/,
 66+  PLUS_SIGN : /^(?:\+)/,
 67+  CARET_SIGN : /^(?:\^)/,
 68+  OPEN_PAREN : /^(?:\()/,
 69+  CLOSE_PAREN : /^(?:\))/,
 70+  GREATER_THAN_SIGN : /^(?:>)/,
 71+  LESS_THAN_SIGN : /^(?:<)/,
 72+  DOUBLE_QUOTE : /^(?:")/,
 73+  SINGLE_QUITE : /^(?:')/,
 74+  EXCLAMATION_POINT : /^(?:!)/,
 75+  EQUALS_SIGN : /^(?:=)/,
 76+  PERCENT_SIGN : /^(?:%)/,
 77+  POUND:  /^(?:\#)/,
 78+  ERROR : /^(?:#N\/A|#NUM\!|#NULL\!|#DIV\/0\!|#VALUE\!|#REF\!|#ERROR)/,
 79+  END : /^(?:$)/
 80+};
 81+
 82+
 83+// Sequential rules to use when parsing a given input.
 84+const RulesSeq = [
 85+  Rules.WHITE_SPACE,
 86+  Rules.DOUBLE_QUOTES,
 87+  Rules.SINGLE_QUOTES,
 88+  Rules.FORMULA_NAME,
 89+  Rules.$_A1_CELL,
 90+  Rules.A1_CELL,
 91+  Rules.FORMULA_NAME_SIMPLE,
 92+  Rules.VARIABLE,
 93+  Rules.SIMPLE_VARIABLE,
 94+  Rules.INTEGER,
 95+  Rules.OPEN_ARRAY,
 96+  Rules.CLOSE_ARRAY,
 97+  Rules.DOLLAR_SIGN,
 98+  Rules.AMPERSAND_SIGN,
 99+  Rules.SINGLE_WHITESPACE,
100+  Rules.PERIOD,
101+  Rules.COLON,
102+  Rules.SEMI_COLON,
103+  Rules.COMMA,
104+  Rules.ASTERISK,
105+  Rules.FORWARD_SLASH,
106+  Rules.MINUS_SIGN,
107+  Rules.PLUS_SIGN,
108+  Rules.CARET_SIGN,
109+  Rules.OPEN_PAREN,
110+  Rules.CLOSE_PAREN,
111+  Rules.GREATER_THAN_SIGN,
112+  Rules.LESS_THAN_SIGN,
113+  Rules.DOUBLE_QUOTE,
114+  Rules.SINGLE_QUITE,
115+  Rules.EXCLAMATION_POINT,
116+  Rules.EQUALS_SIGN,
117+  Rules.PERCENT_SIGN,
118+  Rules.POUND,
119+  Rules.ERROR,
120+  Rules.END
121+];
122+
123+
124+enum Symbol {
125+  ACCEPT = 0,
126+  END = 1,
127+  ERROR = 2,
128+  EXPRESSIONS = 3,
129+  EXPRESSION = 4,
130+  EOF = 5,
131+  VARIABLE = 6,
132+  VARIABLE_SEQUENCE = 7,
133+  NUMBER = 8,
134+  STRING = 9,
135+  FORMULA = 10,
136+  BOOLEAN = 11,
137+  CELL_REF = 12,
138+  FIXED_CELL_REF = 13,
139+  CELL = 14,
140+  OPEN_ARRAY = 15,
141+  CLOSE_ARRAY = 16,
142+  PERIOD = 17,
143+  AMPERSAND = 18,
144+  EQUALS = 19,
145+  PLUS = 20,
146+  OPEN_PAREN = 21,
147+  CLOSE_PAREN = 22,
148+  LESS_THAN = 23,
149+  GREATER_THAN = 24,
150+  MINUS = 25,
151+  ASTERISK = 26,
152+  DIVIDE = 27,
153+  CARROT = 28,
154+  COLON = 29,
155+  SEMI_COLON = 30,
156+  COMMA = 31,
157+  PERCENT = 32,
158+  POUND = 33,
159+  EXCLAMATION_POINT = 34,
160+  WHITE_SPACE = 35
161+}
162+
163+const SYMBOL_NAME_TO_INDEX = {
164+  "ACCEPT": Symbol.ACCEPT,
165+  "END": Symbol.END,
166+  "ERROR": Symbol.ERROR,
167+  "EXPRESSIONS": Symbol.EXPRESSIONS,
168+  "EXPRESSION": Symbol.EXPRESSION,
169+  "EOF": Symbol.EOF,
170+  "VARIABLE": Symbol.VARIABLE,
171+  "VARIABLE_SEQUENCE": Symbol.VARIABLE_SEQUENCE,
172+  "NUMBER": Symbol.NUMBER,
173+  "STRING": Symbol.STRING,
174+  "FORMULA": Symbol.FORMULA,
175+  "CELL_REF": Symbol.CELL_REF,
176+  "FIXED_CELL_REF": Symbol.FIXED_CELL_REF,
177+  "CELL": Symbol.CELL,
178+  "OPEN_ARRAY": Symbol.OPEN_ARRAY,
179+  "CLOSE_ARRAY": Symbol.CLOSE_ARRAY,
180+  "PERIOD": Symbol.PERIOD,
181+  "&": Symbol.AMPERSAND,
182+  "=": Symbol.EQUALS,
183+  "+": Symbol.PLUS,
184+  "(": Symbol.OPEN_PAREN,
185+  ")": Symbol.CLOSE_PAREN,
186+  "<": Symbol.LESS_THAN,
187+  ">": Symbol.GREATER_THAN,
188+  "-": Symbol.MINUS,
189+  "*": Symbol.ASTERISK,
190+  "/": Symbol.DIVIDE,
191+  "^": Symbol.CARROT,
192+  ":": Symbol.COLON,
193+  ";": Symbol.SEMI_COLON,
194+  ",": Symbol.COMMA,
195+  "%": Symbol.PERCENT,
196+  "#": Symbol.POUND,
197+  "!": Symbol.EXCLAMATION_POINT,
198+  "WHITE_SPACE": Symbol.WHITE_SPACE
199+};
200+
201+
202+
203+/**
204+ * Actions to take when processing tokens one by one. We're always either taking the next token, reducing our current
205+ * tokens, or accepting and returning.
206+ */
207+const SHIFT = 1;
208+const REDUCE = 2;
209+const ACCEPT = 3;
210+
211+const enum ReduceActions {
212+  NO_ACTION = 0,
213+  RETURN_LAST = 1,
214+  CALL_VARIABLE = 2,
215+  AS_NUMBER = 3,
216+  AS_STRING = 4,
217+  AMPERSAND = 5,
218+  EQUALS = 6,
219+  PLUS = 7,
220+  LAST_NUMBER = 8,
221+  LTE = 9,
222+  GTE = 10,
223+  NOT_EQ = 11,
224+  NOT = 12,
225+  GT = 13,
226+  LT = 14,
227+  MINUS = 15,
228+  MULTIPLY = 16,
229+  DIVIDE = 17,
230+  TO_POWER = 18,
231+  AS_ERROR = 19,
232+  TO_NUMBER_NAN_AS_ZERO = 20,
233+  CALL_FUNCTION_LAST_BLANK = 21,
234+  FIXED_CELL_VAL = 22,
235+  FIXED_CELL_RANGE_VAL = 23,
236+  CELL_VALUE = 24,
237+  CELL_RANGE_VALUE = 25,
238+  PERCENT = 26
239+}
240+
241+/**
242+ * Represents the length to reduce the stack by, and the token index value that will replace those tokens in the stack.
243+ */
244+class ReductionPair {
245+  private lengthToReduceStackBy : number;
246+  private replacementTokenIndex : number;
247+  constructor(replacementTokenIndex : number, length : number) {
248+    this.lengthToReduceStackBy = length;
249+    this.replacementTokenIndex = replacementTokenIndex;
250+  }
251+
252+  /**
253+   * Get the number representing the length to reduce the stack by.
254+   * @returns {number}
255+   */
256+  getLengthToReduceStackBy() : number {
257+    return this.lengthToReduceStackBy;
258+  }
259+
260+  /**
261+   * Get the replacement token index.
262+   * @returns {number}
263+   */
264+  getReplacementTokenIndex() : number {
265+    return this.replacementTokenIndex;
266+  }
267+}
268+
269+/**
270+ * Productions is used to look up both the number to use when reducing the stack (productions[x][1]) and the semantic
271+ * value that will replace the tokens in the stack (productions[x][0]).
272+ * @type {Array<ReductionPair>}
273+ *
274+ * Maps a ProductionRule to the appropriate number of previous tokens to use in a reduction action.
275+ */
276+let productions : Array<ReductionPair> = [];
277+productions[ReduceActions.NO_ACTION] = null;
278+productions[ReduceActions.RETURN_LAST] = new ReductionPair(3, 2);
279+productions[ReduceActions.CALL_VARIABLE] = new ReductionPair(4, 1);
280+productions[ReduceActions.AS_NUMBER] = new ReductionPair(4, 1);
281+productions[ReduceActions.AS_STRING] = new ReductionPair(4, 1);
282+productions[ReduceActions.AMPERSAND] = new ReductionPair(4, 3);
283+productions[ReduceActions.EQUALS] = new ReductionPair(4, 3);
284+productions[ReduceActions.PLUS] = new ReductionPair(4, 3);
285+productions[ReduceActions.LAST_NUMBER] = new ReductionPair(4, 3);
286+productions[ReduceActions.LTE] = new ReductionPair(4, 4);
287+productions[ReduceActions.GTE] = new ReductionPair(4, 4);
288+productions[ReduceActions.NOT_EQ] = new ReductionPair(4, 4);
289+productions[ReduceActions.NOT] = new ReductionPair(4, 3);
290+productions[ReduceActions.GT] = new ReductionPair(4, 3);
291+productions[ReduceActions.LT] = new ReductionPair(4, 3);
292+productions[ReduceActions.MINUS] = new ReductionPair(4, 3);
293+productions[ReduceActions.MULTIPLY] = new ReductionPair(4, 3);
294+productions[ReduceActions.DIVIDE] = new ReductionPair(4, 3);
295+productions[ReduceActions.TO_POWER] = new ReductionPair(4, 3);
296+productions[ReduceActions.TO_NUMBER_NAN_AS_ZERO] = new ReductionPair(4, 2);
297+productions[ReduceActions.CALL_FUNCTION_LAST_BLANK] = new ReductionPair(4, 3);
298+productions[ReduceActions.FIXED_CELL_VAL] = new ReductionPair(25, 1);
299+productions[ReduceActions.FIXED_CELL_RANGE_VAL] = new ReductionPair(25, 3);
300+productions[ReduceActions.CELL_VALUE] = new ReductionPair(25, 1);
301+productions[ReduceActions.CELL_RANGE_VALUE] = new ReductionPair(25, 3);
302+productions[ReduceActions.PERCENT] = new ReductionPair(24, 3);
303+productions[ReduceActions.AS_ERROR] = new ReductionPair(4, 1);
304+const PRODUCTIONS = productions;
305+
306+
307+const enum Tree {
308+  START = 0,
309+  FOLLOWS_NUMBER = 1,
310+  FOLLOWS_STRING = 2,
311+  FOLLOWS_BOOL = 3,
312+  FOLLOWS_ERROR = 4,
313+  FOLLOWS_FORMULA = 5,
314+  FOLLOWS_PLUS = 6,
315+  FOLLOWS_MINUS = 7,
316+  FOLLOWS_ASTERISK = 8,
317+  FOLLOWS_SLASH = 9,
318+  FOLLOWS_CARROT = 10,
319+  FOLLOWS_AMPERSAND = 11,
320+  FOLLOWS_PERCENT = 12,
321+  FOLLOWS_PERIOD = 13,
322+  FOLLOWS_LESS_THAN = 14,
323+  FOLLOWS_GREATER_THAN = 15,
324+  FOLLOWS_EQUALS = 16,
325+  FOLLOWS_COMMA = 17,
326+  FOLLOWS_OPEN_PAREN = 18,
327+  FOLLOWS_CLOSE_PAREN = 19,
328+  FOLLOWS_CELL_REF = 20,
329+  FOLLOWS_FIXED_CELL_REF = 21,
330+  FOLLOWS_CELL_RANGE_REF = 22,
331+  FOLLOWS_FIXED_CELL_RANGE_REF = 23,
332+  FOLLOWS_OPEN_ARRAY = 24,
333+  FOLLOWS_CLOSE_ARRAY = 25,
334+  TERMINATE = 26
335+}
336+
337+/**
338+ * Array of to map rules to to LexActions and other rules. A single index in the object (e.g. `{2: 13}`) indicates the
339+ * rule object to follow for the next token, while an array (e.g. `{23: [1, ReduceActions.LTE]}`) indicates the action to be taken,
340+ * and the rule object to follow after the action.
341+ */
342+let table = [];
343+// All functions in the spreadsheet start with a 0-token.
344+table[Tree.START] = ObjectBuilder
345+  .add(Symbol.NUMBER, Tree.FOLLOWS_NUMBER)
346+  .add(Symbol.STRING, null)
347+  .add(Symbol.BOOLEAN, null)
348+  .add(Symbol.FORMULA, null)
349+  .add(Symbol.CELL_REF, null)
350+  .add(Symbol.FIXED_CELL_REF, null)
351+  .add(Symbol.POUND, null)
352+  .add(Symbol.OPEN_ARRAY, null)
353+  .add(Symbol.OPEN_PAREN, null)
354+  .add(Symbol.PLUS, null)
355+  .add(Symbol.MINUS, null)
356+  .add(Symbol.PERIOD, null)
357+  .add(Symbol.WHITE_SPACE, null)
358+  .add(Symbol.END, null)
359+  .build();
360+table[Tree.FOLLOWS_NUMBER] = ObjectBuilder
361+  .add(Symbol.PLUS, null)
362+  .add(Symbol.MINUS, null)
363+  .add(Symbol.ASTERISK, null)
364+  .add(Symbol.DIVIDE, null)
365+  .add(Symbol.CARROT, null)
366+  .add(Symbol.PERCENT, null)
367+  .add(Symbol.AMPERSAND, null)
368+  .add(Symbol.GREATER_THAN, null)
369+  .add(Symbol.LESS_THAN, null)
370+  .add(Symbol.EQUALS, null)
371+  .add(Symbol.COMMA, null)
372+  .add(Symbol.CLOSE_PAREN, null)
373+  .add(Symbol.CLOSE_ARRAY, null)
374+  .add(Symbol.WHITE_SPACE, null)
375+  .add(Symbol.END, null)
376+  .build();
377+table[Tree.FOLLOWS_STRING] = ObjectBuilder
378+  .add(Symbol.PLUS, null)
379+  .add(Symbol.MINUS, null)
380+  .add(Symbol.ASTERISK, null)
381+  .add(Symbol.DIVIDE, null)
382+  .add(Symbol.CARROT, null)
383+  .add(Symbol.PERCENT, null)
384+  .add(Symbol.AMPERSAND, null)
385+  .add(Symbol.GREATER_THAN, null)
386+  .add(Symbol.LESS_THAN, null)
387+  .add(Symbol.EQUALS, null)
388+  .add(Symbol.COMMA, null)
389+  .add(Symbol.CLOSE_PAREN, null)
390+  .add(Symbol.CLOSE_ARRAY, null)
391+  .add(Symbol.WHITE_SPACE, null)
392+  .add(Symbol.END, null)
393+  .build();
394+table[Tree.FOLLOWS_BOOL] = ObjectBuilder
395+  .add(Symbol.PLUS, null)
396+  .add(Symbol.MINUS, null)
397+  .add(Symbol.ASTERISK, null)
398+  .add(Symbol.DIVIDE, null)
399+  .add(Symbol.CARROT, null)
400+  .add(Symbol.PERCENT, null)
401+  .add(Symbol.AMPERSAND, null)
402+  .add(Symbol.GREATER_THAN, null)
403+  .add(Symbol.LESS_THAN, null)
404+  .add(Symbol.EQUALS, null)
405+  .add(Symbol.COMMA, null)
406+  .add(Symbol.CLOSE_PAREN, null)
407+  .add(Symbol.CLOSE_ARRAY, null)
408+  .add(Symbol.WHITE_SPACE, null)
409+  .add(Symbol.END, null)
410+  .build();
411+table[Tree.FOLLOWS_ERROR] = ObjectBuilder
412+  .add(Symbol.PLUS, null)
413+  .add(Symbol.MINUS, null)
414+  .add(Symbol.ASTERISK, null)
415+  .add(Symbol.DIVIDE, null)
416+  .add(Symbol.CARROT, null)
417+  .add(Symbol.PERCENT, null)
418+  .add(Symbol.AMPERSAND, null)
419+  .add(Symbol.GREATER_THAN, null)
420+  .add(Symbol.LESS_THAN, null)
421+  .add(Symbol.EQUALS, null)
422+  .add(Symbol.WHITE_SPACE, null)
423+  .add(Symbol.END, null)
424+  .build();
425+table[Tree.FOLLOWS_FORMULA] = ObjectBuilder
426+  .add(Symbol.NUMBER, null)
427+  .add(Symbol.STRING, null)
428+  .add(Symbol.BOOLEAN, null)
429+  .add(Symbol.FORMULA, null)
430+  .add(Symbol.CELL_REF, null)
431+  .add(Symbol.FIXED_CELL_REF, null)
432+  .add(Symbol.PERIOD, null) // TODO: Do we really need period? Why can't we capture this as a number w/ the rule-regex?
433+  .add(Symbol.ERROR, null)
434+  .add(Symbol.POUND, null)
435+  .add(Symbol.PLUS, null)
436+  .add(Symbol.MINUS, null)
437+  .add(Symbol.OPEN_PAREN, null)
438+  .add(Symbol.OPEN_ARRAY, null)
439+  .add(Symbol.WHITE_SPACE, null)
440+  .add(Symbol.END, null)
441+  .build();
442+table[Tree.FOLLOWS_PLUS] = ObjectBuilder
443+  .add(Symbol.NUMBER, null)
444+  .add(Symbol.STRING, null)
445+  .add(Symbol.BOOLEAN, null)
446+  .add(Symbol.PLUS, null)
447+  .add(Symbol.MINUS, null)
448+  .add(Symbol.PERIOD, null)
449+  .add(Symbol.CELL_REF, null)
450+  .add(Symbol.FIXED_CELL_REF, null)
451+  .add(Symbol.POUND, null)
452+  .add(Symbol.FORMULA, null)
453+  .add(Symbol.OPEN_PAREN, null)
454+  .add(Symbol.OPEN_ARRAY, null)
455+  .add(Symbol.WHITE_SPACE, null)
456+  .build();
457+table[Tree.FOLLOWS_MINUS] = ObjectBuilder
458+  .add(Symbol.NUMBER, null)
459+  .add(Symbol.STRING, null)
460+  .add(Symbol.BOOLEAN, null)
461+  .add(Symbol.PLUS, null)
462+  .add(Symbol.MINUS, null)
463+  .add(Symbol.PERIOD, null)
464+  .add(Symbol.CELL_REF, null)
465+  .add(Symbol.FIXED_CELL_REF, null)
466+  .add(Symbol.POUND, null)
467+  .add(Symbol.FORMULA, null)
468+  .add(Symbol.OPEN_PAREN, null)
469+  .add(Symbol.OPEN_ARRAY, null)
470+  .add(Symbol.WHITE_SPACE, null)
471+  .build();
472+table[Tree.FOLLOWS_ASTERISK] = ObjectBuilder
473+  .add(Symbol.NUMBER, null)
474+  .add(Symbol.STRING, null)
475+  .add(Symbol.BOOLEAN, null)
476+  .add(Symbol.PLUS, null)
477+  .add(Symbol.MINUS, null)
478+  .add(Symbol.PERIOD, null)
479+  .add(Symbol.CELL_REF, null)
480+  .add(Symbol.FIXED_CELL_REF, null)
481+  .add(Symbol.POUND, null)
482+  .add(Symbol.FORMULA, null)
483+  .add(Symbol.OPEN_PAREN, null)
484+  .add(Symbol.OPEN_ARRAY, null)
485+  .add(Symbol.WHITE_SPACE, null)
486+  .build();
487+table[Tree.FOLLOWS_SLASH] = ObjectBuilder
488+  .add(Symbol.NUMBER, null)
489+  .add(Symbol.STRING, null)
490+  .add(Symbol.BOOLEAN, null)
491+  .add(Symbol.PLUS, null)
492+  .add(Symbol.MINUS, null)
493+  .add(Symbol.PERIOD, null)
494+  .add(Symbol.CELL_REF, null)
495+  .add(Symbol.FIXED_CELL_REF, null)
496+  .add(Symbol.POUND, null)
497+  .add(Symbol.FORMULA, null)
498+  .add(Symbol.OPEN_PAREN, null)
499+  .add(Symbol.OPEN_ARRAY, null)
500+  .add(Symbol.WHITE_SPACE, null)
501+  .build();
502+table[Tree.FOLLOWS_CARROT] = ObjectBuilder
503+  .add(Symbol.NUMBER, null)
504+  .add(Symbol.STRING, null)
505+  .add(Symbol.BOOLEAN, null)
506+  .add(Symbol.PLUS, null)
507+  .add(Symbol.MINUS, null)
508+  .add(Symbol.PERIOD, null)
509+  .add(Symbol.CELL_REF, null)
510+  .add(Symbol.FIXED_CELL_REF, null)
511+  .add(Symbol.POUND, null)
512+  .add(Symbol.FORMULA, null)
513+  .add(Symbol.OPEN_PAREN, null)
514+  .add(Symbol.OPEN_ARRAY, null)
515+  .add(Symbol.WHITE_SPACE, null)
516+  .build();
517+table[Tree.FOLLOWS_AMPERSAND] = ObjectBuilder
518+  .add(Symbol.NUMBER, null)
519+  .add(Symbol.STRING, null)
520+  .add(Symbol.BOOLEAN, null)
521+  .add(Symbol.PLUS, null)
522+  .add(Symbol.MINUS, null)
523+  .add(Symbol.PERIOD, null)
524+  .add(Symbol.CELL_REF, null)
525+  .add(Symbol.FIXED_CELL_REF, null)
526+  .add(Symbol.POUND, null)
527+  .add(Symbol.FORMULA, null)
528+  .add(Symbol.OPEN_PAREN, null)
529+  .add(Symbol.OPEN_ARRAY, null)
530+  .add(Symbol.WHITE_SPACE, null)
531+  .build();
532+table[Tree.FOLLOWS_PERCENT] = ObjectBuilder
533+  .add(Symbol.PLUS, null)
534+  .add(Symbol.MINUS, null)
535+  .add(Symbol.ASTERISK, null)
536+  .add(Symbol.DIVIDE, null)
537+  .add(Symbol.CARROT, null)
538+  .add(Symbol.AMPERSAND, null)
539+  .add(Symbol.COMMA, null)
540+  .add(Symbol.OPEN_PAREN, null)
541+  .add(Symbol.OPEN_ARRAY, null)
542+  .add(Symbol.WHITE_SPACE, null)
543+  .add(Symbol.END, null)
544+  .build();
545+table[Tree.FOLLOWS_PERIOD] = ObjectBuilder
546+  .add(Symbol.PLUS, null)
547+  .add(Symbol.MINUS, null)
548+  .add(Symbol.ASTERISK, null)
549+  .add(Symbol.DIVIDE, null)
550+  .add(Symbol.CARROT, null)
551+  .add(Symbol.PERCENT, null)
552+  .add(Symbol.AMPERSAND, null)
553+  .add(Symbol.GREATER_THAN, null)
554+  .add(Symbol.LESS_THAN, null)
555+  .add(Symbol.EQUALS, null)
556+  .add(Symbol.WHITE_SPACE, null)
557+  .add(Symbol.END, null)
558+  .build();
559+table[Tree.FOLLOWS_LESS_THAN] = ObjectBuilder
560+  .add(Symbol.NUMBER, Tree.FOLLOWS_NUMBER)
561+  .add(Symbol.STRING, null)
562+  .add(Symbol.BOOLEAN, null)
563+  .add(Symbol.FORMULA, null)
564+  .add(Symbol.CELL_REF, null)
565+  .add(Symbol.FIXED_CELL_REF, null)
566+  .add(Symbol.ERROR, null)
567+  .add(Symbol.OPEN_ARRAY, null)
568+  .add(Symbol.OPEN_PAREN, null)
569+  .add(Symbol.PLUS, null)
570+  .add(Symbol.MINUS, null)
571+  .add(Symbol.PERIOD, null)
572+  .add(Symbol.WHITE_SPACE, null)
573+  .add(Symbol.END, null)
574+  .build();
575+table[Tree.FOLLOWS_GREATER_THAN] = ObjectBuilder
576+  .add(Symbol.NUMBER, Tree.FOLLOWS_NUMBER)
577+  .add(Symbol.STRING, null)
578+  .add(Symbol.BOOLEAN, null)
579+  .add(Symbol.FORMULA, null)
580+  .add(Symbol.CELL_REF, null)
581+  .add(Symbol.FIXED_CELL_REF, null)
582+  .add(Symbol.ERROR, null)
583+  .add(Symbol.OPEN_ARRAY, null)
584+  .add(Symbol.OPEN_PAREN, null)
585+  .add(Symbol.PLUS, null)
586+  .add(Symbol.MINUS, null)
587+  .add(Symbol.PERIOD, null)
588+  .add(Symbol.WHITE_SPACE, null)
589+  .add(Symbol.END, null)
590+  .build();;
591+table[Tree.FOLLOWS_EQUALS] = ObjectBuilder
592+  .add(Symbol.NUMBER, Tree.FOLLOWS_NUMBER)
593+  .add(Symbol.STRING, null)
594+  .add(Symbol.BOOLEAN, null)
595+  .add(Symbol.FORMULA, null)
596+  .add(Symbol.CELL_REF, null)
597+  .add(Symbol.FIXED_CELL_REF, null)
598+  .add(Symbol.ERROR, null)
599+  .add(Symbol.OPEN_ARRAY, null)
600+  .add(Symbol.OPEN_PAREN, null)
601+  .add(Symbol.PLUS, null)
602+  .add(Symbol.MINUS, null)
603+  .add(Symbol.PERIOD, null)
604+  .add(Symbol.WHITE_SPACE, null)
605+  .add(Symbol.END, null)
606+  .build();;
607+table[Tree.FOLLOWS_COMMA] = ObjectBuilder
608+  .add(Symbol.NUMBER, Tree.FOLLOWS_NUMBER)
609+  .add(Symbol.STRING, null)
610+  .add(Symbol.BOOLEAN, null)
611+  .add(Symbol.FORMULA, null)
612+  .add(Symbol.CELL_REF, null)
613+  .add(Symbol.FIXED_CELL_REF, null)
614+  .add(Symbol.ERROR, null)
615+  .add(Symbol.PLUS, null)
616+  .add(Symbol.MINUS, null)
617+  .add(Symbol.PERIOD, null)
618+  .add(Symbol.OPEN_PAREN, null)
619+  .add(Symbol.OPEN_ARRAY, null)
620+  .add(Symbol.WHITE_SPACE, null)
621+  .add(Symbol.END, null)
622+  .build();
623+table[Tree.FOLLOWS_OPEN_PAREN] = ObjectBuilder
624+  .add(Symbol.NUMBER, Tree.FOLLOWS_NUMBER)
625+  .add(Symbol.STRING, null)
626+  .add(Symbol.BOOLEAN, null)
627+  .add(Symbol.FORMULA, null)
628+  .add(Symbol.CELL_REF, null)
629+  .add(Symbol.FIXED_CELL_REF, null)
630+  .add(Symbol.ERROR, null)
631+  .add(Symbol.PLUS, null)
632+  .add(Symbol.MINUS, null)
633+  .add(Symbol.PERIOD, null)
634+  .add(Symbol.OPEN_PAREN, null)
635+  .add(Symbol.OPEN_ARRAY, null)
636+  .add(Symbol.WHITE_SPACE, null)
637+  .build();
638+table[Tree.FOLLOWS_CLOSE_PAREN] = ObjectBuilder
639+  .add(Symbol.PLUS, null)
640+  .add(Symbol.MINUS, null)
641+  .add(Symbol.ASTERISK, null)
642+  .add(Symbol.DIVIDE, null)
643+  .add(Symbol.PERCENT, null)
644+  .add(Symbol.CARROT, null)
645+  .add(Symbol.COMMA, null)
646+  .add(Symbol.CLOSE_ARRAY, null)
647+  .add(Symbol.WHITE_SPACE, null)
648+  .add(Symbol.END, null)
649+  .build();
650+table[Tree.FOLLOWS_CELL_REF] = ObjectBuilder
651+  .add(Symbol.PLUS, null)
652+  .add(Symbol.MINUS, null)
653+  .add(Symbol.ASTERISK, null)
654+  .add(Symbol.DIVIDE, null)
655+  .add(Symbol.CARROT, null)
656+  .add(Symbol.PERCENT, null)
657+  .add(Symbol.AMPERSAND, null)
658+  .add(Symbol.GREATER_THAN, null)
659+  .add(Symbol.LESS_THAN, null)
660+  .add(Symbol.EQUALS, null)
661+  .add(Symbol.COMMA, null)
662+  .add(Symbol.CLOSE_PAREN, null)
663+  .add(Symbol.CLOSE_ARRAY, null)
664+  .add(Symbol.WHITE_SPACE, null)
665+  .add(Symbol.END, null)
666+  .build();
667+table[Tree.FOLLOWS_FIXED_CELL_REF] = ObjectBuilder
668+  .add(Symbol.PLUS, null)
669+  .add(Symbol.MINUS, null)
670+  .add(Symbol.ASTERISK, null)
671+  .add(Symbol.DIVIDE, null)
672+  .add(Symbol.CARROT, null)
673+  .add(Symbol.PERCENT, null)
674+  .add(Symbol.AMPERSAND, null)
675+  .add(Symbol.GREATER_THAN, null)
676+  .add(Symbol.LESS_THAN, null)
677+  .add(Symbol.EQUALS, null)
678+  .add(Symbol.COMMA, null)
679+  .add(Symbol.CLOSE_PAREN, null)
680+  .add(Symbol.CLOSE_ARRAY, null)
681+  .add(Symbol.WHITE_SPACE, null)
682+  .add(Symbol.END, null)
683+  .build();
684+table[Tree.FOLLOWS_CELL_RANGE_REF] = ObjectBuilder
685+  .add(Symbol.PLUS, null)
686+  .add(Symbol.MINUS, null)
687+  .add(Symbol.ASTERISK, null)
688+  .add(Symbol.DIVIDE, null)
689+  .add(Symbol.CARROT, null)
690+  .add(Symbol.PERCENT, null)
691+  .add(Symbol.AMPERSAND, null)
692+  .add(Symbol.GREATER_THAN, null)
693+  .add(Symbol.LESS_THAN, null)
694+  .add(Symbol.EQUALS, null)
695+  .add(Symbol.COMMA, null)
696+  .add(Symbol.CLOSE_PAREN, null)
697+  .add(Symbol.CLOSE_ARRAY, null)
698+  .add(Symbol.WHITE_SPACE, null)
699+  .add(Symbol.END, null)
700+  .build();
701+table[Tree.FOLLOWS_FIXED_CELL_RANGE_REF] = ObjectBuilder
702+  .add(Symbol.PLUS, null)
703+  .add(Symbol.MINUS, null)
704+  .add(Symbol.ASTERISK, null)
705+  .add(Symbol.DIVIDE, null)
706+  .add(Symbol.CARROT, null)
707+  .add(Symbol.PERCENT, null)
708+  .add(Symbol.AMPERSAND, null)
709+  .add(Symbol.GREATER_THAN, null)
710+  .add(Symbol.LESS_THAN, null)
711+  .add(Symbol.EQUALS, null)
712+  .add(Symbol.COMMA, null)
713+  .add(Symbol.CLOSE_PAREN, null)
714+  .add(Symbol.CLOSE_ARRAY, null)
715+  .add(Symbol.WHITE_SPACE, null)
716+  .add(Symbol.END, null)
717+  .build();
718+table[Tree.FOLLOWS_OPEN_ARRAY] = ObjectBuilder
719+  .add(Symbol.NUMBER, Tree.FOLLOWS_NUMBER)
720+  .add(Symbol.STRING, null)
721+  .add(Symbol.BOOLEAN, null)
722+  .add(Symbol.FORMULA, null)
723+  .add(Symbol.CELL_REF, null)
724+  .add(Symbol.FIXED_CELL_REF, null)
725+  .add(Symbol.ERROR, null)
726+  .add(Symbol.PLUS, null)
727+  .add(Symbol.MINUS, null)
728+  .add(Symbol.PERIOD, null)
729+  .add(Symbol.OPEN_PAREN, null)
730+  .add(Symbol.OPEN_ARRAY, null)
731+  .add(Symbol.CLOSE_ARRAY, null)
732+  .add(Symbol.WHITE_SPACE, null)
733+  .build();
734+table[Tree.FOLLOWS_CLOSE_ARRAY] = ObjectBuilder
735+  .add(Symbol.PLUS, null)
736+  .add(Symbol.MINUS, null)
737+  .add(Symbol.ASTERISK, null)
738+  .add(Symbol.DIVIDE, null)
739+  .add(Symbol.PERCENT, null)
740+  .add(Symbol.CARROT, null)
741+  .add(Symbol.COMMA, null)
742+  .add(Symbol.CLOSE_PAREN, null)
743+  .add(Symbol.CLOSE_ARRAY, null)
744+  .add(Symbol.WHITE_SPACE, null)
745+  .add(Symbol.END, null)
746+  .build();
747+
748+
749+table[Tree.TERMINATE] = undefined; // Terminate the end.
750\ No newline at end of file
751diff --git a/src/Parser/ParserConstants.ts b/src/Parser/ParserConstants.ts
752index 07a908e..31bd4b4 100644
753--- a/src/Parser/ParserConstants.ts
754+++ b/src/Parser/ParserConstants.ts
755@@ -1,3 +1,6 @@
756+import {
757+  ObjectBuilder
758+} from "./ObjectBuilder";
759 
760 // Rules represent the Regular Expressions that will be used in sequence to match a given input to the Parser.
761 const WHITE_SPACE_RULE = /^(?:\s+)/; // rule 0
762@@ -318,7 +321,7 @@ symbolIndexToName[Symbol.ASTERISK] = "*";
763 symbolIndexToName[Symbol.DIVIDE] = "/";
764 symbolIndexToName[Symbol.CARROT] = "^";
765 symbolIndexToName[Symbol.FUNCTION] = "FUNCTION";
766-symbolIndexToName[Symbol.FIXEDCELL] = "FIXEDCELL";
767+symbolIndexToName[Symbol.FIXEDCELL] = "FIXED_CELL_REF";
768 symbolIndexToName[Symbol.COLON] = ";";
769 symbolIndexToName[Symbol.COMMA] = ",";
770 symbolIndexToName[Symbol.VARIABLE] = "VARIABLE";
771@@ -332,23 +335,6 @@ const SYMBOL_INDEX_TO_NAME = symbolIndexToName;
772 
773 
774 
775-class ObjectBuilder {
776-  public o : Object = {};
777-
778-  public static add(k, v) : ObjectBuilder {
779-    let m = new ObjectBuilder();
780-    m.o[k.toString()] = v;
781-    return m;
782-  }
783-  public add(k, v) : ObjectBuilder {
784-    this.o[k.toString()] = v;
785-    return this;
786-  }
787-  public build() : Object {
788-    return this.o;
789-  }
790-}
791-
792 /**
793  * Array of to map rules to to LexActions and other rules. A single index in the object (e.g. `{2: 13}`) indicates the
794  * rule object to follow for the next token, while an array (e.g. `{23: [1, ReduceActions.LTE]}`) indicates the action to be taken,