context counting # # Regular Definitions # rl rl_ws /[ \t\n\r\v]+/ rl rl_id /[a-zA-Z_][a-zA-Z0-9_]*/ rl rl_num /[0-9]+/ # # Tokens # lex # Ignore whitespace. ignore /rl_ws/ literal `; # Tokens. token id /rl_id/ token number /rl_num/ end # # Global Data # target: int count: int # # Productions # def get_target [number] { count = 0 target = r1.data.atoi() print( 'target: ', target, '\n' ) } # Arbitrary item. def item [number] | [id] def count_items [one_item count_items] | [] def one_item [item] { count = count + 1 if count > target { reject } print( 'ITEM\n' ) } # Wrapper which prevents short lists from getting through if the parser # encounters an error and needs to backtrack over counted list. def counted_list [get_target count_items] { print( 'trying: ', count, ' for: ', target, '\n' ) if count < target { reject } } def start [counted_list*] { for List: counted_list in lhs { match List [Count: number Items: count_items] print( 'num items: ', Count.data.atoi(), '\n' ) i: int = 1 for Item: item in Items { print( ' item ', i, ': ', ^Item, '\n' ) i = i + 1 } } print( '*** SUCCESS ***\n' ) } end # counting Counting: counting = new counting() parse counting::start( Counting )[ stdin ] ##### IN ##### 3 1 b c 1 1 0 3 a b c ##### EXP ##### target: 3 ITEM ITEM ITEM ITEM trying: 3 for: 3 target: 1 ITEM ITEM trying: 1 for: 1 target: 0 ITEM trying: 0 for: 0 target: 3 ITEM ITEM ITEM trying: 3 for: 3 num items: 3 item 1: 1 item 2: b item 3: c num items: 1 item 1: 1 num items: 0 num items: 3 item 1: a item 2: b item 3: c *** SUCCESS ***