Я написал библиотеку для сопоставления строк с набором шаблонов, и теперь я могу легко встраивать лексические сканеры в программы на Си.
Я знаю, что существует множество хорошо зарекомендовавших себя инструментов для создания лексических сканеров (lex и re2c, просто чтобы назвать первые два, которые приходят на ум) Этот вопрос не о лексерах, а о лучшем подходе к расширению Синтаксис C . Пример лексера - это конкретный случай общей проблемы.
Я вижу два возможных решения:
- напишите препроцессор , который преобразует исходный файл со встроенным лексером в простой файл C и, возможно, в набор других файлов, которые будут использоваться при компиляции.
- написать набор макросов C для представления лексеров в более удобочитаемой форме.
Я уже сделал оба, но вопрос в следующем: «Какой из них вы бы назвали лучшей практикой в соответствии со следующими критериями?»
- читаемость. Логика лексера должна быть ясной и простой для понимания
- ремонтопригодность. Поиск и исправление ошибки не должно быть кошмаром!
- Помехи в процессе сборки. Препроцессору потребуется дополнительный шаг в процессе сборки, препроцессор должен быть в пути и т. Д. И т. Д.
Другими словами, если вам приходилось поддерживать или писать программу, использующую один из двух подходов, какой из них вас разочарует меньше?
В качестве примера приведем лексер для следующей задачи:
- Суммирование всех чисел (может быть в десятичной форме, включая экспоненциальную, например, 1.3E-4.2)
- Пропуск строк (двойные и одинарные кавычки)
- пропустить списки (аналогично спискам LISP: (3 4 (0 1) () 3))
- остановка при обнаружении слова end (регистр не имеет значения) или в конце буфера
В двух стилях.
/**** SCANNER STYLE 1 (preprocessor) ****/
#include "pmx.h"
t = buffer
while (*t) {
switch pmx(t) { /* the preprocessor will handle this */
case "&q" : /* skip strings */
break;
case "&f<?=eE>&F" : /* sum numbers */
sum += atof(pmx(Start,0));
break;
case "&b()": /* skip lists */
break;
case "&iend" : /* stop processing */
t = "";
break;
case "<.>": /* skip a char and proceed */
break;
}
}
/**** SCANNER STYLE 2 (macros) ****/
#include "pmx.h"
/* There can be up to 128 tokens per scanner with id x80 to xFF */
#define TOK_STRING x81
#define TOK_NUMBER x82
#define TOK_LIST x83
#define TOK_END x84
#define TOK_CHAR x85
pmxScanner( /* pmxScanner() is a pretty complex macro */
buffer
,
pmxTokSet("&q" , TOK_STRING)
pmxTokSet("&f<?=eE>&F" , TOK_NUMBER)
pmxTokSet("&b()" , TOK_LIST)
pmxTokSet("&iend" , TOK_END)
pmxTokSet("<.>" , TOK_CHAR)
,
pmxTokCase(TOK_STRING) : /* skip strings */
continue;
pmxTokCase(TOK_NUMBER) : /* sum numbers */
sum += atof(pmxTokStart(0));
continue;
pmxTokCase(TOK_LIST): /* skip lists */
continue;
pmxTokCase(TOK_END) : /* stop processing */
break;
pmxTokCase(TOK_CHAR) : /* skip a char and proceed */
continue;
);
Если кого-то интересует текущая реализация, код здесь: http://sites.google.com/site/clibutl.