1 # Copyright (C) 2007-2008, Parrot Foundation.
6 PCT::Grammar - base grammar with useful rules
10 grammar MyGrammar is PCT::Grammar;
12 rule abc { [ word | <panic: word not found> ] }
15 [ \' <string_literal: '> \'
16 | \" <string_literal: "> \"
22 This file implements C<PCT::Grammar>, which is a basic grammar object
23 with a few useful methods for parsing thrown in.
29 =item panic(match [, message, ...] )
31 Throws an exception at the current point of the match, with message
32 as part of the exception payload. The message doesn't end with
33 a newline, then the line number and offset of the match are
38 .namespace [ 'PCT';'Grammar' ]
40 .sub 'onload' :anon :init :load
41 load_bytecode 'PGE.pbc'
42 load_bytecode 'PGE/Util.pbc'
44 p6meta = new 'P6metaclass'
45 p6meta.'new_class'('PCT::Grammar', 'parent'=>'PGE::Grammar')
46 $P0 = split '::', 'PCT::Grammar'
48 $P1 = get_hll_global ['PGE';'Util'], 'die'
49 $P0.'add_method'('panic', $P1)
54 =item FAILGOAL($goal [, 'dba'=>dba])
56 Invoked when goal matching fails to find the goal. Builds an appropriate
57 error message and delegates the rest to C<panic>.
61 .sub 'FAILGOAL' :method
63 .param pmc options :named :slurpy
67 ## if no dba supplied, use the name of the caller sub
72 .tailcall self.'panic'("Unable to parse ", dba, "; couldn't find final ", goal)
78 Here we overload the item() method from PGE::Match to
79 throw an exception if a result object hasn't been set.
85 obj = getattribute self, '$!ast'
86 unless null obj goto end
87 die "No result object"
95 Special-purpose rule to return true if we're in the middle
96 of a word -- i.e., if the previous and next character are
97 both "word characters". This is roughly equivalent to
98 C<< <?after \w><?before \w> >> except it's much quicker.
99 In particular, C<< <!ww> >> can be used by :sigspace rules
100 to enforce whitespace between lexical words.
104 .include 'cclass.pasm'
110 $P0 = get_hll_global ['PGE'], 'Match'
111 (mob, pos, target) = $P0.'new'(self)
112 if pos == 0 goto fail
113 $I0 = is_cclass .CCLASS_WORD, target, pos
116 $I0 = is_cclass .CCLASS_WORD, target, $I1
124 .sub 'string_literal' :method
126 .param pmc adverbs :slurpy :named
128 ## create a new match object, get the new match position
130 .local int pos, lastpos, stoplen
131 .local string target, escapechars
132 (mob, pos, target) = self.'new'(self)
133 lastpos = length target
134 stoplen = length stop
135 $S0 = substr stop, 0, 1
136 escapechars = concat "\\", $S0
138 ## leave space for close delimiter
141 ## now initialize and loop through target
143 .local string literal, litchar
147 ## if we're beyond the last possible position, fail
148 if pos > lastpos goto fail
150 ## if ending delimiter, then we're done
151 $S0 = substr target, pos, stoplen
152 if $S0 == stop goto literal_end
153 if pos >= lastpos goto fail
155 ## get next character in literal
156 litchar = substr target, pos, 1
159 ## add non-escape characters to literal
160 if litchar != "\\" goto add_litchar
162 ## look at the next character, if it's always escaped, add it and
164 .local string escaped
165 escaped = substr target, pos, 1
166 $I0 = index escapechars, escaped
167 if $I0 < 0 goto interpolated_escape
173 ## if not double-quoted delim, no interpolation
174 if stop != '"' goto add_litchar
177 $I0 = index "abefnrt0xdo", litchar
178 if $I0 < 0 goto add_litchar
180 ## if it's one of "xdo", then handle that specially
181 if $I0 >= 8 goto literal_xdo
183 litchar = substr "\a\b\e\f\n\r\t\0", $I0, 1
187 ## handle \x, \d, and \o escapes. start by converting
188 ## the 'o', 'd', or 'x' into 8, 10, or 16 (yes, it's hack
189 ## but it works). Then loop through the characters that
190 ## follow to compute the integer value of the codepoint,
191 ## and add that codepoint to our literal.
192 .local int base, codepoint, isbracketed
193 base = index ' o d x', litchar
195 $S0 = substr target, pos, 1
196 isbracketed = iseq $S0, '['
198 literal_xdo_char_loop:
199 $S0 = substr target, pos, 1
200 $I0 = index '0123456789abcdef', $S0
201 if $I0 < 0 goto literal_xdo_char_end
202 if $I0 >= base goto literal_xdo_char_end
206 goto literal_xdo_char_loop
207 literal_xdo_char_end:
210 unless isbracketed goto literal_xdo_end
211 if $S0 == ']' goto literal_xdo_end
212 if $S0 != ',' goto fail
215 goto literal_xdo_char_loop
238 # vim: expandtab shiftwidth=4 ft=pir: