summaryrefslogtreecommitdiff
path: root/test/til.lm
blob: 6a93ab356069948fc8b5a8ddb66f30db7a29c97c (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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
##### LM #####
lex
	literal `var `if `then `else `while `do `for `read `write
			`end `to `goto

	literal `:= `!= `; `+ `- `* `/ `= `( `) `:

	ignore /'//' [^\n]* '\n'/
	ignore /[\n\t ]+/
	token id /[a-zA-Z_]+/
	token integernumber /[0-9]+/
	token stringlit /'"' [^"]* '"'/
end

def program
	[statement*]

def statement
	[declaration]
|	[assignment_statement]
|	[if_statement]
|	[while_statement]
|	[do_statement]
|	[for_statement]
|	[read_statement]
|	[write_statement]
|	[labelled_statement]
|	[goto_statement]

def declaration
	[`var id `;]

def assignment_statement
	[id `:= expression `;]

def if_statement
	[`if expression `then statement* opt_else_statement `end]

def opt_else_statement
	[`else statement*]
|	[]

def while_statement
	[`while expression `do statement* `end]

def do_statement
	[`do statement* `while expression `;]

def for_statement
	[`for id `:= expression `to expression `do statement* `end]

def read_statement
	[`read id `;]

def write_statement
	[`write expression `;]

def expression
	[term]
|	[expression eqop term]

def eqop [`=] | [`!=]

def term
	[factor]
|	[term addop factor]

def addop [`+] | [`-]

def factor
	[primary]
|	[factor mulop primary]

def mulop [`*] | [`/]

def primary
	[id]
|	[lit]
|	[`( expression `)]

def lit
	[integernumber]
|	[stringlit]

def labelled_statement
	[id `: statement]

def goto_statement
	[`goto id `;]

parse P: program[stdin]

#for S:statement* in P
#{
#	if match S [L0: id ':'
#			First: statement
#			Rest: statement*]
#	{
#		for Check: statement* in Rest
#		{
#			if match Check
#				['if' E: expression 'then'
#					'goto' Targ: id ';'
#				'end'
#				T: statement*]
#			{
#				# This truncates Rest
#				Check = construct statement* []
#
#				# Replace the labeled statement through to the goto with a
#				# do ... while.
#				S = construct statement*
#					['do'
#						First
#						Rest
#					'while' E ';'
#					T]
#				break
#			}
#		}
#	}
#}

for S: statement* in P
{
    if match S [Label: id `:
            First: statement
            Rest: statement*]
    {
		Expr: expression
		Following: statement*

		# Look though the remaining statements for a goto back to the label.
		# The repeat iterator yields only top-level statement lists. It
		# restricts our search to the same nesting depth as the label.
        for Check: statement* in Rest
        {
            if match Check
                [`if E: expression `then
                    `goto L:id `;
                `end
                SL: statement*]
            {
				Expr = E
				Following = SL

				# Check iterates over tails of Rest. Assigning an empty list
				# to check truncates the Rest list. What we cut off is saved in
				# Following (excluding the if statement).
                Check = construct statement* []
            }
        }

		# If a goto was found, then perform the rewrite.
		if ( Expr )
		{
            # Replace the labelled statement through to the goto
			# with a do ... while.
            S = construct statement* [
				"do
                "	[^First]
                "	[^Rest]
                "while [^Expr];
                Following]
		}
    }
}

print( P )
##### IN #####

var a;
a := 1;

head:

a := a + 1;
c := d;

if a = 10 then
	goto head;
end

hi := there;
##### EXP #####

var a;
a := 1;

do
	a := a + 1;
	c := d;
while a = 10;
hi := there;