##### LM ##### 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/ # Tokens. token id /rl_id/ token number /rl_num/ end # # Global Data # target: int # # Productions # def get_target [number] { match lhs [Number:number] target = Number.data.atoi() } # Arbitrary item. def item [number] | [id] # Type definition for the count_items nonterminal. def count_items count: int # List production one. The condition stops the # greedy list when it has gone too far. [count_items item] { # Pass up the data lhs.count = r1.count + 1 if lhs.count > target { reject } } # List production two, the base. | [] { lhs.count = 0 } # 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] { if r2.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 } } } end # counting cons Counting: counting[] parse counting::start(Counting)[ stdin ] ##### IN ##### 3 1 b c 1 1 0 3 a b c ##### EXP ##### 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