Skip to content

Commit a1a9205

Browse files
committed
Сделано C89-совместимым, так, что gcc -pedantic -ansi -std=c89 -Wall не выдает предупреждений.
1 parent 4fba56b commit a1a9205

File tree

2 files changed

+113
-23
lines changed

2 files changed

+113
-23
lines changed

passes/generate.js

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,11 @@ function generateCCode(ast) {
101101
}
102102
function makeFunctionBuilder(varName, retType, argType) {
103103
function n1(i, args) { return varName + i + '(' + args.join(', ') + ')'; }
104-
function n2(v, i) { return retType + ' ' + n1(i, v.params.map(function(p) { return argType + ' ' + p; })); }
104+
function n2(v, i) {
105+
var p = v.params.map(function(p) { return argType + ' ' + p; });
106+
p.unshift('struct Context* context');
107+
return retType + ' ' + n1(i, p);
108+
}
105109
var storage = [];
106110
return {
107111
add: function(namespace, params, code, args) {
@@ -112,6 +116,7 @@ function generateCCode(ast) {
112116
&& f.body === code;
113117
});
114118

119+
args.unshift('ctx');
115120
return n1(index < 0 ? storage.push({ namespace: namespace, params: params, body: code }) - 1 : index, args);
116121
},
117122

@@ -285,23 +290,73 @@ function generateCCode(ast) {
285290
];
286291
var builder = new CodeBuilder(code);
287292
builder.pushAll(literals.vars());
288-
builder.push('/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/');
293+
builder.push('/*~~~~~~~~~~~~~~~~~~~~ CHAR CLASSES ~~~~~~~~~~~~~~~~~~~~~*/');
289294
builder.pushAll(charClasses.vars());
290-
builder.push('/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/');
295+
builder.push('/*~~~~~~~~~~~~~~~~ EXPECTED DEFINITIONS ~~~~~~~~~~~~~~~~~*/');
291296
builder.pushAll(expected.vars());
292-
builder.push('/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/');
297+
builder.push('/*~~~~~~~~~~~~~~ RULE FORWARD DECLARATIONS ~~~~~~~~~~~~~~*/');
293298
builder.pushAll(node.rules.map(function(r) { return rDef(r) + ';'; }));
294-
builder.push('/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/');
299+
builder.push('/*~~~~~~~~~~~~~~~~~~~~~ PREDICATES ~~~~~~~~~~~~~~~~~~~~~~*/');
295300
builder.pushAll(predicates.defines());
296-
builder.push('/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/');
301+
builder.push('/*~~~~~~~~~~~~~~~~~~~~~~~ ACTIONS ~~~~~~~~~~~~~~~~~~~~~~~*/');
297302
builder.pushAll(actions.defines());
298-
builder.push('/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/');
303+
builder.push('/*~~~~~~~~~~~~~~~~~~~~~~~~ RULES ~~~~~~~~~~~~~~~~~~~~~~~~*/');
299304
builder.pushAll(rules);
300305
builder.push('/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/');
301-
builder.indent('PARSER_API struct Result* parse(struct Range* input) {');
306+
builder.indent('PARSER_API struct Result* parse(struct Range* input, struct Range* startRule, void* options) {');
302307
// Создаем таблицу для поиска правил разбора по имени.
303308
builder.pushAll(createLookupTable(node.rules.map(function(r) { return r.name; })));
309+
builder.push(
310+
'struct Context ctx = {',
311+
' { 0, 0 },',
312+
' { 0, 1, 1 },',
313+
' { 0, { 0, 1, 1 }, 0, 0 },',
314+
' 0',
315+
'};',
316+
'ctx.input.begin = input->begin;',
317+
'ctx.input.end = input->end;',
318+
'ctx.options = options;',
319+
'if (startRule) {',
320+
' const struct ParseFunc* func = findRule(funcs, sizeof(funcs) / sizeof(funcs[0]), startRule);',
321+
' if (func == 0) { return 0; }',
322+
' return (*func->func)(&ctx);',
323+
'}',
324+
'return ' + (node.rules.length > 0 ? (r(node.rules[0].name) + '(&ctx)') : '0')+ ';'
325+
);
304326
builder.dedent('}');
327+
builder.push(
328+
'PARSER_API struct Result* parse2(const char* input, unsigned int len, struct Range* startRule, void* options) {',
329+
' struct Range r;',
330+
' r.begin = input;',
331+
' r.end = input + len;',
332+
' return parse(&r, startRule, options);',
333+
'}'
334+
);
335+
builder.push(
336+
'PARSER_API struct Result* parse3(struct Range* input, const char* startRule, unsigned int len, void* options) {',
337+
' if (startRule) {',
338+
' struct Range s;',
339+
' s.begin = startRule;',
340+
' s.end = startRule + len;',
341+
' return parse(input, &s, options);',
342+
' }',
343+
' return parse(input, 0, options);',
344+
'}'
345+
);
346+
builder.push(
347+
'PARSER_API struct Result* parse4(const char* input, unsigned int inputLen, const char* startRule, unsigned int startRuleLen, void* options) {',
348+
' struct Range r;',
349+
' r.begin = input;',
350+
' r.end = input + inputLen;',
351+
' if (startRule) {',
352+
' struct Range s;',
353+
' s.begin = startRule;',
354+
' s.end = startRule + startRuleLen;',
355+
' return parse(&r, &s, options);',
356+
' }',
357+
' return parse(&r, 0, options);',
358+
'}'
359+
);
305360

306361
code.push(
307362
'#undef length',

peg.h

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
/** @file С89-совместимый заголовочный файл для генератора парсеров. */
1+
/** @file С89-совместимый заголовочный файл для генератора парсеров.
2+
`gcc -pedantic -ansi -std=c89` не должен выдавать никаких предупреждений.
3+
*/
24

35
/* Для memcmp. */
46
#include <string.h>
5-
/* Для malloc/calloc/free. */
7+
/* Для malloc/calloc/free/bsearch. */
68
#include <stdlib.h>
79
/* Для va_*, используемых в функции wrap. */
810
#include <stdarg.h>
@@ -34,7 +36,7 @@ struct Result {
3436
/** Количество потомков данного узла. */
3537
unsigned int count;
3638
/** Указатель на потомков данного узла. */
37-
struct Result* childs;
39+
struct Result** childs;
3840
};
3941
/** Содержит позицию в разбираемых данных, как в виде смещения в байтах от начала строки,
4042
так и в виде номеров строки и столбца.
@@ -59,11 +61,11 @@ enum E_EXPECTED_TYPE {
5961
/** Ожидается окончание потока данных. */
6062
E_EX_TYPE_EOF,
6163
/** Пользовательское сообщение об ожидаемых данных. */
62-
E_EX_TYPE_USER,
64+
E_EX_TYPE_USER
6365
};
6466
struct Expected {
6567
enum E_EXPECTED_TYPE type;
66-
char message[0];
68+
const char* message;
6769
};
6870
struct FailInfo {
6971
unsigned int silent;
@@ -81,6 +83,8 @@ struct Context {
8183
struct Pos current;
8284
/** Информация об ошибках разбора. */
8385
struct FailInfo failInfo;
86+
/** Информация, передаваемая пользователем в парсер. Парсером не используется. */
87+
void* options;
8488
};
8589
struct Literal {
8690
/** Длина литерала (массива data). */
@@ -124,9 +128,11 @@ static struct Result NIL = {{0, 0}, 0, 0};
124128
/* Процедуры сопоставления. */
125129
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
126130
int matchLiteral(struct Context* context, const struct Literal* literal) {
127-
const char* begin = context->input.begin + context->current.offset;
128-
const unsigned int inputLen = context->input.end - begin;
129-
/** Если входная строка короче, то она точно не равна литералу. */
131+
const char* begin;
132+
unsigned int inputLen;
133+
begin = context->input.begin + context->current.offset;
134+
inputLen = context->input.end - begin;
135+
/* Если входная строка короче, то она точно не равна литералу. */
130136
return inputLen < literal->len ? 0 : memcmp(begin, literal->data, literal->len) == 0;
131137
}
132138
/**
@@ -135,25 +141,34 @@ int matchLiteral(struct Context* context, const struct Literal* literal) {
135141
@param count Количество элементов в массиве @a ranges.
136142
*/
137143
int matchCharClass(struct Context* context, struct CharClass* cls) {
144+
const char* begin;
138145
assert(context);
139146
assert(context->input.begin);
140147
assert(cls);
141148
assert(cls->single);
142149
assert(cls->range);
143-
const char* begin = context->input.begin + context->current.offset;
150+
151+
begin = context->input.begin + context->current.offset;
144152

145153
/* Если мы еще не в конце входных данных, то пытаемся сматчить текущий символ. */
146154
if (begin < context->input.end) {
147155
/* Выделяем нижнюю половину бит числа с помощью маски. Верхнюю половину получаем, просто
148156
отодвинув ненужную нижнюю половину. */
149-
const unsigned int countLO = cls->counts & ((~0u) >> (sizeof(cls->counts)*4));
150-
const unsigned int countHI = cls->counts >> (sizeof(cls->counts)*4);
151-
const char ch = begin[0];
157+
unsigned int countLO;
158+
unsigned int countHI;
159+
char ch;
152160
unsigned int i;
161+
162+
countLO = cls->counts & ((~0u) >> (sizeof(cls->counts)*4));
163+
countHI = cls->counts >> (sizeof(cls->counts)*4);
164+
ch = begin[0];
153165
/* Класс символов является списком пар, задающих диапазоны символов. */
154166
for (i = 0; i < countLO; ++i) {
155-
const char b = cls->range[i*2];
156-
const char e = cls->range[i*2 + 1];
167+
char b;
168+
char e;
169+
170+
b = cls->range[i*2];
171+
e = cls->range[i*2 + 1];
157172
/* Строгая проверка, т.к. если начало и конец совпадают, то это единственный символ
158173
и он должен быть в cls->single. */
159174
assert(b < e);
@@ -319,4 +334,24 @@ struct Result* wrap(struct Context* context, unsigned int pos, unsigned int coun
319334

320335
va_end(results);
321336
return r;
322-
};
337+
}
338+
static int findRuleCompatator(const struct Range* name, const struct ParseFunc* entry) {
339+
unsigned int len;
340+
assert(name);
341+
assert(name->begin);
342+
assert(name->end);
343+
assert(entry);
344+
len = name->end - name->begin;
345+
if (len < entry->len) { return -1; }
346+
if (len > entry->len) { return +1; }
347+
return memcmp(name->begin, entry->name, len);
348+
}
349+
const struct ParseFunc* findRule(const struct ParseFunc* table, size_t count, const struct Range* name) {
350+
typedef int (*Comparator)(const void*, const void*);
351+
assert(table);
352+
assert(name);
353+
return (const struct ParseFunc*)bsearch(
354+
name, table, count, sizeof(table[0]),
355+
(Comparator)&findRuleCompatator
356+
);
357+
}

0 commit comments

Comments
 (0)