Commits

allison committed 6dce484

Some cleanups and fixes to get grammars and definitions working.

Comments (0)

Files changed (1)

Spix/PEG/Parser.pir

     .param int pos
     .param string name
     .param pmc memo
+    .local pmc memo_store
 
     $P0 = getattribute self, 'memo'
+    if null $P0 goto no_memo
     $I0 = exists $P0[pos]
     if $I0 goto pos_exists
-    $P1 = new ['Hash']
+    memo_store = new ['Hash']
+    $P0[pos] = memo_store
     goto set_memo
   pos_exists:
-    $P1 = $P0[pos]
+    memo_store = $P0[pos]
 
   set_memo:
-    $P1[name] = memo
+    memo_store[name] = memo
+  no_memo:
 .end
 
 .sub 'get_memo' :method
     tree = self.'get_memo'(pos, name)
     unless null tree goto got_tree
 
+    $I0 = self.'length'()
+    if pos >= $I0 goto got_tree
+
     $I0 = ord input, pos
     $I1 = ord value
 
     .param string input
     .param int pos
     .local pmc tree, children, definitions
+    .local int new_pos
+    new_pos = pos
 
     tree = self.'get_memo'(pos, 'Grammar')
     unless null tree goto got_tree
   no_leading_space:
 
     # First definition is required
-    $I0 = self.'pos'()
-    $P0 = self.'Definition'(input, $I0)
-    if null $P0 goto got_tree
+    new_pos = self.'pos'()
+    $P0 = self.'Definition'(input, new_pos)
+    if null $P0 goto warn_definition
     definitions = new ['ResizablePMCArray']
     push children, definitions
     push definitions, $P0
 
     # Following definitions are optional
   definition_loop:
-    $I0 = self.'pos'()
-    $P0 = self.'Definition'(input, $I0)
+    new_pos = self.'pos'()
+    $P0 = self.'Definition'(input, new_pos)
     if null $P0 goto definition_end
     push definitions, $P0
     goto definition_loop
   definition_end:
 
     # End-of-file is required
-    $I0 = self.'pos'()
-    $P0 = self.'EndOfFile'(input, $I0)
-    if null $P0 goto got_tree
+    new_pos = self.'pos'()
+    $P0 = self.'EndOfFile'(input, new_pos)
+    if null $P0 goto warn_endoffile
     push children, $P0
 
+
     tree = self.'new_node'(children :flat, 'name'=>'Grammar', 'pos'=>pos)
     self.'set_memo'(pos, 'Grammar', tree)
 
   got_tree:
     .return (tree)
+
+  warn_definition:
+    printerr "warning: Unable to match the top-level definition.\n"
+    goto got_tree
+  warn_endoffile:
+    printerr "warning: Unable to match the end of the file.\n"
+    goto got_tree
 .end
 
 .sub 'Definition' :method
     .param string input
     .param int pos
     .local pmc tree, children
+    .local int new_pos
+    new_pos = pos
 
     tree = self.'get_memo'(pos, 'Definition')
     unless null tree goto got_tree
     children = new ['ResizablePMCArray']
 
     # Identifier is required
-    $P0 = self.'Identifier'(input, pos)
+    $P0 = self.'Identifier'(input, new_pos)
+    if null $P0 goto warn_identifier
+    push children, $P0
+    new_pos = self.'pos'()
+
+    # LEFTARROW is required
+    $P0 = self.'LEFTARROW'(input, new_pos)
     if null $P0 goto got_tree
     push children, $P0
-
-    # LEFTARROW is required
-    $P0 = self.'LEFTARROW'(input, pos)
-    if null $P0 goto got_tree
-    push children, $P0
+    new_pos = self.'pos'()
 
     # Expression is required
-    $P0 = self.'Expression'(input, pos)
+    $P0 = self.'Expression'(input, new_pos)
     if null $P0 goto got_tree
     push children, $P0
 
 
   got_tree:
     .return (tree)
+
+  warn_identifier:
+    printerr "warning: Unmatched identifier at position "
+    printerr new_pos
+    printerr ".\n"
+    goto got_tree
 .end
 
 .sub 'Expression' :method
     $S0 = chr $I0
 
     if $S0 != "'" goto try_double
+    literal_string = $S0
   single_loop:
     inc new_pos
     $P0 = self.'Char'(input, new_pos)
     if null $P0 goto got_tree
     $S0 = $P0.'src'()
+    literal_string .= $S0
     if $S0 == "'" goto single_end
-    literal_string .= $S0
     push children, $P0
     goto single_loop
   single_end:
-    inc new_pos
+    new_pos = self.'pos'()
     goto matched
   backtrack_single:
     self.'pos'(pos)
 
   try_double:
     if $S0 != '"' goto got_tree
+    inc new_pos
   double_loop:
-    inc new_pos
     $P0 = self.'Char'(input, new_pos)
     if null $P0 goto got_tree
     $S0 = $P0.'src'()
     if $S0 == '"' goto double_end
     literal_string .= $S0
     push children, $P0
+    new_pos = self.'pos'()
     goto double_loop
   double_end:
     inc new_pos
     goto got_tree
 
   matched:
-    self.'pos'(new_pos)
+    # Consume optional space
+    new_pos = self.'pos'()
+    $P0 = self.'Spacing'(input, new_pos)
+
     tree = self.'new_node'(children :flat, 'name'=>'Literal', 'src'=>literal_string, 'pos'=>pos)
     self.'set_memo'(pos, 'Literal', tree)
 
     $I0 = ord input, new_pos
     $S1 = chr $I0
     if $S1 == "-" goto matched_second
-    .return(tree)
+    goto got_tree
 
   matched_second:
+    # Spacing is optional
     inc new_pos
+    $P0 = self.'Spacing'(input, new_pos)
+    if null $P0 goto no_leading_space
+    new_pos = self.'pos'()
+  no_leading_space:
+
     self.'pos'(new_pos)
     $S2 = $S0 . $S1
     tree = self.'new_node'('name'=>'LEFTARROW', 'src'=>$S2, 'pos'=>pos)
     .local pmc tree
     .local string src
     .local pmc children
-    .local int new_pos, have_match
+    .local int new_pos
     new_pos = pos
     src = ''
-    have_match = 0
-    null children
 
     tree = self.'get_memo'(pos, 'Spacing')
     unless null tree goto got_tree
+    children = new ['ResizablePMCArray']
 
   children_loop:
     $P0 = self.'Space'(input, new_pos)
     if null $P0 goto children_done
-    have_match = 1
-
-    unless null children goto got_children
-    children = new ['ResizablePMCArray']
-  got_children:
-    
     push children, $P0
     $S0 = $P0.'src'()
     src .= $S0
     goto children_loop
   children_done:
 
-    unless have_match goto got_tree
-
     $I0 = children
     unless $I0 goto got_tree
 
-    tree = self.'new_node'('name'=>'Spacing', 'src'=>src, 'pos'=>pos)
-    tree.'children'(children)
+    tree = self.'new_node'(children :flat, 'name'=>'Spacing', 'src'=>src, 'pos'=>pos)
     self.'set_memo'(pos, 'Spacing', tree)
 
   got_tree:
     unless null tree goto got_tree
 
     $I0 = self.'length'()
-    if pos == $I0 goto got_tree
+    if pos >= $I0 goto got_tree
 
     $I0 = ord input, pos
     $S0 = chr $I0