summaryrefslogtreecommitdiff
path: root/test/counting1.lm
blob: ef35603ebbb428341fe260fe4273bbd61e20ea5b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
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 ]