meta_compile 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +1 -1
- data/Rakefile +111 -0
- data/bin/meta_compile +2 -2
- data/bootstrap/bootstrap.c +260 -0
- data/bootstrap/bootstrapped_c +0 -0
- data/bootstrap/compile_syntax_c_to_ruby.c +214 -0
- data/bootstrap/meta_for_c.txt +38 -0
- data/bootstrap/meta_for_ruby.txt +1 -1
- data/bootstrap/meta_for_ruby_single_flag.txt +35 -0
- data/bootstrap/meta_r +0 -0
- data/bootstrap/meta_ruby_compiler.rb +230 -0
- data/bootstrap/meta_ruby_compiler2.rb +230 -0
- data/bootstrap/meta_ruby_compiler3.rb +230 -0
- data/bootstrap/meta_ruby_compiler_from_c.rb +230 -0
- data/bootstrap/original_support.h +242 -0
- data/bootstrap/support.h +242 -0
- data/meta_compile.gemspec +13 -0
- metadata +16 -2
@@ -0,0 +1,230 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "strscan"
|
3
|
+
class RMetaII
|
4
|
+
def compile(str, out)
|
5
|
+
@i, @o = StringScanner.new(str), out
|
6
|
+
compile_program
|
7
|
+
end
|
8
|
+
def compile_outarg
|
9
|
+
begin
|
10
|
+
@i.scan /\s*/; s="$"; l=s.length;
|
11
|
+
@f = (@i.peek(l) == s) ? (@t=s; @i.pos += l) : nil
|
12
|
+
if @f
|
13
|
+
@o.print "@o.print @t"
|
14
|
+
@o.print "\n"
|
15
|
+
end
|
16
|
+
break if @f
|
17
|
+
@i.scan /\s*/; @f = @t = @i.scan /\047[^\047]*\047/
|
18
|
+
if @f
|
19
|
+
@o.print "@o.print "
|
20
|
+
@o.print @t
|
21
|
+
@o.print "\n"
|
22
|
+
end
|
23
|
+
end while false
|
24
|
+
end
|
25
|
+
def compile_out
|
26
|
+
begin
|
27
|
+
@i.scan /\s*/; s="<"; l=s.length;
|
28
|
+
@f = (@i.peek(l) == s) ? (@t=s; @i.pos += l) : nil
|
29
|
+
if @f
|
30
|
+
begin
|
31
|
+
compile_outarg
|
32
|
+
end while @f
|
33
|
+
@f = true
|
34
|
+
raise("error at: " + @i.rest.split("\n")[0]) if !@f
|
35
|
+
@i.scan /\s*/; s=">"; l=s.length;
|
36
|
+
@f = (@i.peek(l) == s) ? (@t=s; @i.pos += l) : nil
|
37
|
+
raise("error at: " + @i.rest.split("\n")[0]) if !@f
|
38
|
+
@o.print "@o.print \"\\n\""
|
39
|
+
@o.print "\n"
|
40
|
+
end
|
41
|
+
end while false
|
42
|
+
end
|
43
|
+
def compile_exp3
|
44
|
+
begin
|
45
|
+
@i.scan /\s*/; @f = @t = @i.scan /[A-Za-z]+[A-Za-z0-9_]+/
|
46
|
+
if @f
|
47
|
+
@o.print "compile_"
|
48
|
+
@o.print @t
|
49
|
+
@o.print "\n"
|
50
|
+
end
|
51
|
+
break if @f
|
52
|
+
@i.scan /\s*/; @f = @t = @i.scan /\047[^\047]*\047/
|
53
|
+
if @f
|
54
|
+
@o.print "@i.scan /\\s*/; s="
|
55
|
+
@o.print @t
|
56
|
+
@o.print "; l=s.length;"
|
57
|
+
@o.print "\n"
|
58
|
+
@o.print "@f = (@i.peek(l) == s) ? (@t=s; @i.pos += l) : nil"
|
59
|
+
@o.print "\n"
|
60
|
+
end
|
61
|
+
break if @f
|
62
|
+
@i.scan /\s*/; s=".id"; l=s.length;
|
63
|
+
@f = (@i.peek(l) == s) ? (@t=s; @i.pos += l) : nil
|
64
|
+
if @f
|
65
|
+
@o.print "@i.scan /\\s*/; @f = @t = @i.scan /[A-Za-z]+[A-Za-z0-9_]+/"
|
66
|
+
@o.print "\n"
|
67
|
+
end
|
68
|
+
break if @f
|
69
|
+
@i.scan /\s*/; s=".string"; l=s.length;
|
70
|
+
@f = (@i.peek(l) == s) ? (@t=s; @i.pos += l) : nil
|
71
|
+
if @f
|
72
|
+
@o.print "@i.scan /\\s*/; @f = @t = @i.scan /\\047[^\\047]*\\047/"
|
73
|
+
@o.print "\n"
|
74
|
+
end
|
75
|
+
break if @f
|
76
|
+
@i.scan /\s*/; s="("; l=s.length;
|
77
|
+
@f = (@i.peek(l) == s) ? (@t=s; @i.pos += l) : nil
|
78
|
+
if @f
|
79
|
+
compile_exp1
|
80
|
+
raise("error at: " + @i.rest.split("\n")[0]) if !@f
|
81
|
+
@i.scan /\s*/; s=")"; l=s.length;
|
82
|
+
@f = (@i.peek(l) == s) ? (@t=s; @i.pos += l) : nil
|
83
|
+
raise("error at: " + @i.rest.split("\n")[0]) if !@f
|
84
|
+
end
|
85
|
+
break if @f
|
86
|
+
@i.scan /\s*/; s=".e"; l=s.length;
|
87
|
+
@f = (@i.peek(l) == s) ? (@t=s; @i.pos += l) : nil
|
88
|
+
if @f
|
89
|
+
@o.print "@f = true"
|
90
|
+
@o.print "\n"
|
91
|
+
end
|
92
|
+
break if @f
|
93
|
+
@i.scan /\s*/; s="*"; l=s.length;
|
94
|
+
@f = (@i.peek(l) == s) ? (@t=s; @i.pos += l) : nil
|
95
|
+
if @f
|
96
|
+
@o.print "begin"
|
97
|
+
@o.print "\n"
|
98
|
+
compile_exp3
|
99
|
+
raise("error at: " + @i.rest.split("\n")[0]) if !@f
|
100
|
+
@o.print "end while @f"
|
101
|
+
@o.print "\n"
|
102
|
+
@o.print "@f = true"
|
103
|
+
@o.print "\n"
|
104
|
+
end
|
105
|
+
end while false
|
106
|
+
end
|
107
|
+
def compile_exp2
|
108
|
+
begin
|
109
|
+
begin
|
110
|
+
compile_exp3
|
111
|
+
if @f
|
112
|
+
@o.print "if @f"
|
113
|
+
@o.print "\n"
|
114
|
+
end
|
115
|
+
break if @f
|
116
|
+
compile_out
|
117
|
+
if @f
|
118
|
+
@o.print "if true"
|
119
|
+
@o.print "\n"
|
120
|
+
end
|
121
|
+
end while false
|
122
|
+
if @f
|
123
|
+
begin
|
124
|
+
begin
|
125
|
+
compile_exp3
|
126
|
+
if @f
|
127
|
+
@o.print "raise(\"error at: \" + @i.rest.split(\"\\n\")[0]) if !@f"
|
128
|
+
@o.print "\n"
|
129
|
+
end
|
130
|
+
break if @f
|
131
|
+
compile_out
|
132
|
+
if @f
|
133
|
+
end
|
134
|
+
end while false
|
135
|
+
end while @f
|
136
|
+
@f = true
|
137
|
+
raise("error at: " + @i.rest.split("\n")[0]) if !@f
|
138
|
+
@o.print "end"
|
139
|
+
@o.print "\n"
|
140
|
+
end
|
141
|
+
end while false
|
142
|
+
end
|
143
|
+
def compile_exp1
|
144
|
+
begin
|
145
|
+
@o.print "begin"
|
146
|
+
@o.print "\n"
|
147
|
+
if true
|
148
|
+
compile_exp2
|
149
|
+
raise("error at: " + @i.rest.split("\n")[0]) if !@f
|
150
|
+
begin
|
151
|
+
begin
|
152
|
+
@i.scan /\s*/; s="|"; l=s.length;
|
153
|
+
@f = (@i.peek(l) == s) ? (@t=s; @i.pos += l) : nil
|
154
|
+
if @f
|
155
|
+
@o.print "break if @f"
|
156
|
+
@o.print "\n"
|
157
|
+
compile_exp2
|
158
|
+
raise("error at: " + @i.rest.split("\n")[0]) if !@f
|
159
|
+
end
|
160
|
+
end while false
|
161
|
+
end while @f
|
162
|
+
@f = true
|
163
|
+
raise("error at: " + @i.rest.split("\n")[0]) if !@f
|
164
|
+
@o.print "end while false"
|
165
|
+
@o.print "\n"
|
166
|
+
end
|
167
|
+
end while false
|
168
|
+
end
|
169
|
+
def compile_rule
|
170
|
+
begin
|
171
|
+
@i.scan /\s*/; @f = @t = @i.scan /[A-Za-z]+[A-Za-z0-9_]+/
|
172
|
+
if @f
|
173
|
+
@o.print "def compile_"
|
174
|
+
@o.print @t
|
175
|
+
@o.print "\n"
|
176
|
+
@i.scan /\s*/; s="="; l=s.length;
|
177
|
+
@f = (@i.peek(l) == s) ? (@t=s; @i.pos += l) : nil
|
178
|
+
raise("error at: " + @i.rest.split("\n")[0]) if !@f
|
179
|
+
compile_exp1
|
180
|
+
raise("error at: " + @i.rest.split("\n")[0]) if !@f
|
181
|
+
@i.scan /\s*/; s=";"; l=s.length;
|
182
|
+
@f = (@i.peek(l) == s) ? (@t=s; @i.pos += l) : nil
|
183
|
+
raise("error at: " + @i.rest.split("\n")[0]) if !@f
|
184
|
+
@o.print "end"
|
185
|
+
@o.print "\n"
|
186
|
+
end
|
187
|
+
end while false
|
188
|
+
end
|
189
|
+
def compile_program
|
190
|
+
begin
|
191
|
+
@i.scan /\s*/; s=".syntax"; l=s.length;
|
192
|
+
@f = (@i.peek(l) == s) ? (@t=s; @i.pos += l) : nil
|
193
|
+
if @f
|
194
|
+
@i.scan /\s*/; @f = @t = @i.scan /[A-Za-z]+[A-Za-z0-9_]+/
|
195
|
+
raise("error at: " + @i.rest.split("\n")[0]) if !@f
|
196
|
+
@o.print "#!/usr/bin/env ruby"
|
197
|
+
@o.print "\n"
|
198
|
+
@o.print "require \"strscan\""
|
199
|
+
@o.print "\n"
|
200
|
+
@o.print "class "
|
201
|
+
@o.print @t
|
202
|
+
@o.print "\n"
|
203
|
+
@o.print "def compile(str, out)"
|
204
|
+
@o.print "\n"
|
205
|
+
@o.print "@i, @o = StringScanner.new(str), out"
|
206
|
+
@o.print "\n"
|
207
|
+
@o.print "compile_program"
|
208
|
+
@o.print "\n"
|
209
|
+
@o.print "end"
|
210
|
+
@o.print "\n"
|
211
|
+
begin
|
212
|
+
compile_rule
|
213
|
+
end while @f
|
214
|
+
@f = true
|
215
|
+
raise("error at: " + @i.rest.split("\n")[0]) if !@f
|
216
|
+
@i.scan /\s*/; s=".end"; l=s.length;
|
217
|
+
@f = (@i.peek(l) == s) ? (@t=s; @i.pos += l) : nil
|
218
|
+
raise("error at: " + @i.rest.split("\n")[0]) if !@f
|
219
|
+
@o.print "end"
|
220
|
+
@o.print "\n"
|
221
|
+
@o.print "begin; puts(\"Use: \" + $0 + \" <in> <out>\"); exit; end if ARGV.length != 2"
|
222
|
+
@o.print "\n"
|
223
|
+
@o.print "File.open(ARGV[1], \"w\") {|f| RMetaII.new.compile(File.read(ARGV[0]), f)}"
|
224
|
+
@o.print "\n"
|
225
|
+
end
|
226
|
+
end while false
|
227
|
+
end
|
228
|
+
end
|
229
|
+
begin; puts("Use: " + $0 + " <in> <out>"); exit; end if ARGV.length != 2
|
230
|
+
File.open(ARGV[1], "w") {|f| RMetaII.new.compile(File.read(ARGV[0]), f)}
|
@@ -0,0 +1,242 @@
|
|
1
|
+
#include <stdlib.h>
|
2
|
+
#include <stdio.h>
|
3
|
+
#include <string.h>
|
4
|
+
|
5
|
+
char *output_name = NULL;
|
6
|
+
FILE *output = NULL;
|
7
|
+
char *source = NULL;
|
8
|
+
int pos = 0;
|
9
|
+
int line = 1;
|
10
|
+
int test_flag = 0;
|
11
|
+
char *token = NULL;
|
12
|
+
|
13
|
+
void skip_whitespace(void)
|
14
|
+
{
|
15
|
+
while (source[pos] == '\x20' || source[pos] == '\t' ||
|
16
|
+
source[pos] == '\r' || source[pos] == '\n') {
|
17
|
+
// increment line counter when new line reached
|
18
|
+
if (source[pos] == '\n') {
|
19
|
+
line++;
|
20
|
+
}
|
21
|
+
pos++;
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
void make_token(int start_pos)
|
26
|
+
{
|
27
|
+
int length = pos - start_pos;
|
28
|
+
free(token);
|
29
|
+
token = malloc(length + 1);
|
30
|
+
token[length] = '\0';
|
31
|
+
memcpy(token, &source[start_pos], length);
|
32
|
+
}
|
33
|
+
|
34
|
+
// emits the currently recognized token
|
35
|
+
void emit_token(void)
|
36
|
+
{
|
37
|
+
int i;
|
38
|
+
// strings are converted to C format
|
39
|
+
if (token[0] == '\'') {
|
40
|
+
fprintf(output, "\"");
|
41
|
+
for (i = 1; token[i] != '\0' && token[i] != '\''; i++) {
|
42
|
+
switch (token[i]) {
|
43
|
+
case '\"':
|
44
|
+
fprintf(output, "\\\"");
|
45
|
+
break;
|
46
|
+
case '\\':
|
47
|
+
fprintf(output, "\\\\");
|
48
|
+
break;
|
49
|
+
default:
|
50
|
+
fprintf(output, "%c", token[i]);
|
51
|
+
break;
|
52
|
+
}
|
53
|
+
}
|
54
|
+
fprintf(output, "\"");
|
55
|
+
return;
|
56
|
+
}
|
57
|
+
// if token is not a string, emit as-is
|
58
|
+
fprintf(output, "%s", token);
|
59
|
+
}
|
60
|
+
|
61
|
+
void emit(const char *str)
|
62
|
+
{
|
63
|
+
fprintf(output, "%s", str);
|
64
|
+
}
|
65
|
+
|
66
|
+
void emit_nl(void)
|
67
|
+
{
|
68
|
+
fprintf(output, "\n");
|
69
|
+
}
|
70
|
+
|
71
|
+
void read_literal(const char *literal)
|
72
|
+
{
|
73
|
+
int entry_pos;
|
74
|
+
int i;
|
75
|
+
|
76
|
+
skip_whitespace();
|
77
|
+
// compare source with the literal
|
78
|
+
entry_pos = pos;
|
79
|
+
i = 0;
|
80
|
+
while (source[pos] != '\0' && literal[i] != '\0' &&
|
81
|
+
source[pos] == literal[i]) {
|
82
|
+
pos++;
|
83
|
+
i++;
|
84
|
+
}
|
85
|
+
// if the end of the literal has been reached, comparison successful
|
86
|
+
if (literal[i] == '\0') {
|
87
|
+
test_flag = 1;
|
88
|
+
make_token(entry_pos);
|
89
|
+
} else {
|
90
|
+
// reset position
|
91
|
+
pos = entry_pos;
|
92
|
+
test_flag = 0;
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
void read_id(void)
|
97
|
+
{
|
98
|
+
int entry_pos;
|
99
|
+
|
100
|
+
skip_whitespace();
|
101
|
+
// recognize initial alphabetic character
|
102
|
+
entry_pos = pos;
|
103
|
+
if (('A' <= source[pos] && source[pos] <= 'A') ||
|
104
|
+
('a' <= source[pos] && source[pos] <= 'z')) {
|
105
|
+
pos++;
|
106
|
+
test_flag = 1;
|
107
|
+
} else {
|
108
|
+
test_flag = 0;
|
109
|
+
return;
|
110
|
+
}
|
111
|
+
// recognize alphanumeric characters
|
112
|
+
while (('A' <= source[pos] && source[pos] <= 'A') ||
|
113
|
+
('a' <= source[pos] && source[pos] <= 'z') ||
|
114
|
+
('0' <= source[pos] && source[pos] <= '9')) {
|
115
|
+
pos++;
|
116
|
+
}
|
117
|
+
// recognition successful, copy into token
|
118
|
+
make_token(entry_pos);
|
119
|
+
}
|
120
|
+
|
121
|
+
void read_number(void)
|
122
|
+
{
|
123
|
+
int entry_pos;
|
124
|
+
|
125
|
+
skip_whitespace();
|
126
|
+
// recognize optional negative sign
|
127
|
+
entry_pos = pos;
|
128
|
+
if (source[pos] == '-') {
|
129
|
+
pos++;
|
130
|
+
}
|
131
|
+
// recognize initial numeric character
|
132
|
+
if ('0' <= source[pos] && source[pos] <= '9') {
|
133
|
+
pos++;
|
134
|
+
test_flag = 1;
|
135
|
+
} else {
|
136
|
+
test_flag = 0;
|
137
|
+
return;
|
138
|
+
}
|
139
|
+
// recognize subsequent numeric characters
|
140
|
+
while ('0' <= source[pos] && source[pos] <= '9') {
|
141
|
+
pos++;
|
142
|
+
}
|
143
|
+
// recognition successful, copy into token
|
144
|
+
make_token(entry_pos);
|
145
|
+
}
|
146
|
+
|
147
|
+
void read_string(void)
|
148
|
+
{
|
149
|
+
int entry_pos;
|
150
|
+
|
151
|
+
skip_whitespace();
|
152
|
+
// recognize initial single quote
|
153
|
+
entry_pos = pos;
|
154
|
+
if (source[pos] == '\'') {
|
155
|
+
pos++;
|
156
|
+
// test_flag is not set as recognition can still fail
|
157
|
+
} else {
|
158
|
+
test_flag = 0;
|
159
|
+
return;
|
160
|
+
}
|
161
|
+
|
162
|
+
// recognize contents
|
163
|
+
while (source[pos] != '\0' && source[pos] != '\'') {
|
164
|
+
// increment line counter when new line reached
|
165
|
+
if (source[pos] == '\n') {
|
166
|
+
line++;
|
167
|
+
}
|
168
|
+
pos++;
|
169
|
+
}
|
170
|
+
|
171
|
+
// recognize final single quote
|
172
|
+
if (source[pos] == '\'') {
|
173
|
+
pos++;
|
174
|
+
test_flag = 1;
|
175
|
+
make_token(entry_pos);
|
176
|
+
} else if (source[pos] == '\0') {
|
177
|
+
// reset position
|
178
|
+
pos = entry_pos;
|
179
|
+
test_flag = 0;
|
180
|
+
}
|
181
|
+
}
|
182
|
+
|
183
|
+
void error_if_false(void)
|
184
|
+
{
|
185
|
+
if (!test_flag) {
|
186
|
+
fprintf(stderr, "error in line %i at token %s\n", line, token);
|
187
|
+
fclose(output);
|
188
|
+
// delete the output file
|
189
|
+
remove(output_name);
|
190
|
+
free(source);
|
191
|
+
free(token);
|
192
|
+
exit(1);
|
193
|
+
}
|
194
|
+
}
|
195
|
+
|
196
|
+
void meta_program(void);
|
197
|
+
void meta_exp1(void);
|
198
|
+
|
199
|
+
int main(int argc, char *argv[])
|
200
|
+
{
|
201
|
+
FILE *input;
|
202
|
+
int length;
|
203
|
+
|
204
|
+
if (argc < 3) {
|
205
|
+
fprintf(stderr, "usage: meta <input> <output>\n");
|
206
|
+
exit(1);
|
207
|
+
}
|
208
|
+
|
209
|
+
// open input and output
|
210
|
+
input = fopen(argv[1], "r");
|
211
|
+
if (input == NULL) {
|
212
|
+
fprintf(stderr, "invalid input file\n");
|
213
|
+
exit(1);
|
214
|
+
}
|
215
|
+
output_name = argv[2];
|
216
|
+
output = fopen(output_name, "w");
|
217
|
+
if (output == NULL) {
|
218
|
+
fprintf(stderr, "invalid output file\n");
|
219
|
+
exit(1);
|
220
|
+
}
|
221
|
+
// read entire input into source
|
222
|
+
fseek(input, 0, SEEK_END);
|
223
|
+
length = (int)ftell(input);
|
224
|
+
fseek(input, 0, SEEK_SET);
|
225
|
+
source = malloc(length + 1);
|
226
|
+
fread(source, 1, length, input);
|
227
|
+
source[length] = '\0';
|
228
|
+
fclose(input);
|
229
|
+
|
230
|
+
// initially we have empty token; token is never NULL
|
231
|
+
token = malloc(1);
|
232
|
+
token[0] = '\0';
|
233
|
+
|
234
|
+
// run meta
|
235
|
+
meta_program();
|
236
|
+
fclose(output);
|
237
|
+
free(source);
|
238
|
+
free(token);
|
239
|
+
return 0;
|
240
|
+
}
|
241
|
+
|
242
|
+
/* end */
|
data/bootstrap/support.h
ADDED
@@ -0,0 +1,242 @@
|
|
1
|
+
#include <stdlib.h>
|
2
|
+
#include <stdio.h>
|
3
|
+
#include <string.h>
|
4
|
+
|
5
|
+
char *output_name = NULL;
|
6
|
+
FILE *output = NULL;
|
7
|
+
char *source = NULL;
|
8
|
+
int pos = 0;
|
9
|
+
int line = 1;
|
10
|
+
int test_flag = 0;
|
11
|
+
char *token = NULL;
|
12
|
+
|
13
|
+
void skip_whitespace(void)
|
14
|
+
{
|
15
|
+
while (source[pos] == '\x20' || source[pos] == '\t' ||
|
16
|
+
source[pos] == '\r' || source[pos] == '\n') {
|
17
|
+
// increment line counter when new line reached
|
18
|
+
if (source[pos] == '\n') {
|
19
|
+
line++;
|
20
|
+
}
|
21
|
+
pos++;
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
void make_token(int start_pos)
|
26
|
+
{
|
27
|
+
int length = pos - start_pos;
|
28
|
+
free(token);
|
29
|
+
token = malloc(length + 1);
|
30
|
+
token[length] = '\0';
|
31
|
+
memcpy(token, &source[start_pos], length);
|
32
|
+
}
|
33
|
+
|
34
|
+
// emits the currently recognized token
|
35
|
+
void emit_token(void)
|
36
|
+
{
|
37
|
+
int i;
|
38
|
+
// strings are converted to C format
|
39
|
+
if (token[0] == '\'') {
|
40
|
+
fprintf(output, "\"");
|
41
|
+
for (i = 1; token[i] != '\0' && token[i] != '\''; i++) {
|
42
|
+
switch (token[i]) {
|
43
|
+
case '\"':
|
44
|
+
fprintf(output, "\\\"");
|
45
|
+
break;
|
46
|
+
case '\\':
|
47
|
+
fprintf(output, "\\\\");
|
48
|
+
break;
|
49
|
+
default:
|
50
|
+
fprintf(output, "%c", token[i]);
|
51
|
+
break;
|
52
|
+
}
|
53
|
+
}
|
54
|
+
fprintf(output, "\"");
|
55
|
+
return;
|
56
|
+
}
|
57
|
+
// if token is not a string, emit as-is
|
58
|
+
fprintf(output, "%s", token);
|
59
|
+
}
|
60
|
+
|
61
|
+
void emit(const char *str)
|
62
|
+
{
|
63
|
+
fprintf(output, "%s", str);
|
64
|
+
}
|
65
|
+
|
66
|
+
void emit_nl(void)
|
67
|
+
{
|
68
|
+
fprintf(output, "\n");
|
69
|
+
}
|
70
|
+
|
71
|
+
void read_literal(const char *literal)
|
72
|
+
{
|
73
|
+
int entry_pos;
|
74
|
+
int i;
|
75
|
+
|
76
|
+
skip_whitespace();
|
77
|
+
// compare source with the literal
|
78
|
+
entry_pos = pos;
|
79
|
+
i = 0;
|
80
|
+
while (source[pos] != '\0' && literal[i] != '\0' &&
|
81
|
+
source[pos] == literal[i]) {
|
82
|
+
pos++;
|
83
|
+
i++;
|
84
|
+
}
|
85
|
+
// if the end of the literal has been reached, comparison successful
|
86
|
+
if (literal[i] == '\0') {
|
87
|
+
test_flag = 1;
|
88
|
+
make_token(entry_pos);
|
89
|
+
} else {
|
90
|
+
// reset position
|
91
|
+
pos = entry_pos;
|
92
|
+
test_flag = 0;
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
void read_id(void)
|
97
|
+
{
|
98
|
+
int entry_pos;
|
99
|
+
|
100
|
+
skip_whitespace();
|
101
|
+
// recognize initial alphabetic character
|
102
|
+
entry_pos = pos;
|
103
|
+
if (('A' <= source[pos] && source[pos] <= 'Z') ||
|
104
|
+
('a' <= source[pos] && source[pos] <= 'z')) {
|
105
|
+
pos++;
|
106
|
+
test_flag = 1;
|
107
|
+
} else {
|
108
|
+
test_flag = 0;
|
109
|
+
return;
|
110
|
+
}
|
111
|
+
// recognize alphanumeric characters
|
112
|
+
while (('A' <= source[pos] && source[pos] <= 'Z') ||
|
113
|
+
('a' <= source[pos] && source[pos] <= 'z') ||
|
114
|
+
('0' <= source[pos] && source[pos] <= '9')) {
|
115
|
+
pos++;
|
116
|
+
}
|
117
|
+
// recognition successful, copy into token
|
118
|
+
make_token(entry_pos);
|
119
|
+
}
|
120
|
+
|
121
|
+
void read_number(void)
|
122
|
+
{
|
123
|
+
int entry_pos;
|
124
|
+
|
125
|
+
skip_whitespace();
|
126
|
+
// recognize optional negative sign
|
127
|
+
entry_pos = pos;
|
128
|
+
if (source[pos] == '-') {
|
129
|
+
pos++;
|
130
|
+
}
|
131
|
+
// recognize initial numeric character
|
132
|
+
if ('0' <= source[pos] && source[pos] <= '9') {
|
133
|
+
pos++;
|
134
|
+
test_flag = 1;
|
135
|
+
} else {
|
136
|
+
test_flag = 0;
|
137
|
+
return;
|
138
|
+
}
|
139
|
+
// recognize subsequent numeric characters
|
140
|
+
while ('0' <= source[pos] && source[pos] <= '9') {
|
141
|
+
pos++;
|
142
|
+
}
|
143
|
+
// recognition successful, copy into token
|
144
|
+
make_token(entry_pos);
|
145
|
+
}
|
146
|
+
|
147
|
+
void read_string(void)
|
148
|
+
{
|
149
|
+
int entry_pos;
|
150
|
+
|
151
|
+
skip_whitespace();
|
152
|
+
// recognize initial single quote
|
153
|
+
entry_pos = pos;
|
154
|
+
if (source[pos] == '\'') {
|
155
|
+
pos++;
|
156
|
+
// test_flag is not set as recognition can still fail
|
157
|
+
} else {
|
158
|
+
test_flag = 0;
|
159
|
+
return;
|
160
|
+
}
|
161
|
+
|
162
|
+
// recognize contents
|
163
|
+
while (source[pos] != '\0' && (source[pos] != '\'' || (source[pos] == '\'' && source[pos-1] == '\\'))) {
|
164
|
+
// increment line counter when new line reached
|
165
|
+
if (source[pos] == '\n') {
|
166
|
+
line++;
|
167
|
+
}
|
168
|
+
pos++;
|
169
|
+
}
|
170
|
+
|
171
|
+
// recognize final single quote
|
172
|
+
if (source[pos] == '\'') {
|
173
|
+
pos++;
|
174
|
+
test_flag = 1;
|
175
|
+
make_token(entry_pos);
|
176
|
+
} else if (source[pos] == '\0') {
|
177
|
+
// reset position
|
178
|
+
pos = entry_pos;
|
179
|
+
test_flag = 0;
|
180
|
+
}
|
181
|
+
}
|
182
|
+
|
183
|
+
void error_if_false(void)
|
184
|
+
{
|
185
|
+
if (!test_flag) {
|
186
|
+
fprintf(stderr, "error in line %i at token %s\n", line, token);
|
187
|
+
fclose(output);
|
188
|
+
// delete the output file
|
189
|
+
remove(output_name);
|
190
|
+
free(source);
|
191
|
+
free(token);
|
192
|
+
exit(1);
|
193
|
+
}
|
194
|
+
}
|
195
|
+
|
196
|
+
void meta_program(void);
|
197
|
+
void meta_exp1(void);
|
198
|
+
|
199
|
+
int main(int argc, char *argv[])
|
200
|
+
{
|
201
|
+
FILE *input;
|
202
|
+
int length;
|
203
|
+
|
204
|
+
if (argc < 3) {
|
205
|
+
fprintf(stderr, "usage: meta <input> <output>\n");
|
206
|
+
exit(1);
|
207
|
+
}
|
208
|
+
|
209
|
+
// open input and output
|
210
|
+
input = fopen(argv[1], "r");
|
211
|
+
if (input == NULL) {
|
212
|
+
fprintf(stderr, "invalid input file\n");
|
213
|
+
exit(1);
|
214
|
+
}
|
215
|
+
output_name = argv[2];
|
216
|
+
output = fopen(output_name, "w");
|
217
|
+
if (output == NULL) {
|
218
|
+
fprintf(stderr, "invalid output file\n");
|
219
|
+
exit(1);
|
220
|
+
}
|
221
|
+
// read entire input into source
|
222
|
+
fseek(input, 0, SEEK_END);
|
223
|
+
length = (int)ftell(input);
|
224
|
+
fseek(input, 0, SEEK_SET);
|
225
|
+
source = malloc(length + 1);
|
226
|
+
fread(source, 1, length, input);
|
227
|
+
source[length] = '\0';
|
228
|
+
fclose(input);
|
229
|
+
|
230
|
+
// initially we have empty token; token is never NULL
|
231
|
+
token = malloc(1);
|
232
|
+
token[0] = '\0';
|
233
|
+
|
234
|
+
// run meta
|
235
|
+
meta_program();
|
236
|
+
fclose(output);
|
237
|
+
free(source);
|
238
|
+
free(token);
|
239
|
+
return 0;
|
240
|
+
}
|
241
|
+
|
242
|
+
/* end */
|
@@ -0,0 +1,13 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'meta_compile'
|
3
|
+
s.version = '0.0.6'
|
4
|
+
s.date = '2012-11-25'
|
5
|
+
s.summary = "meta compiler framework"
|
6
|
+
s.description = "A meta compilation framework à la Meta-II by Val Schorre"
|
7
|
+
s.authors = ["Robert Feldt"]
|
8
|
+
s.email = 'robert.feldt@gmail.com'
|
9
|
+
s.files = ["Rakefile", "README.md", "meta_compile.gemspec"] + Dir.glob("bin/*") + Dir.glob("bootstrap/*")
|
10
|
+
s.executables << 'meta_compile'
|
11
|
+
s.homepage =
|
12
|
+
'http://rubygems.org/gems/meta_compile'
|
13
|
+
end
|