Как да замените макроси с анализатор, базиран на граматика?

Имам нужда от парсер за екзотичен език за програмиране. Написах граматика за него и използвах генератор на анализатор (PEGjs), за да генерирам анализатора. Това работи перфектно... с изключение на едно нещо: макроси (които заместват контейнер с предварително дефиниран текст). Не знам как да интегрирам това в граматика. Нека илюстрирам проблема:

Примерна програма за анализиране обикновено изглежда така:

instructionA parameter1, parameter2
instructionB parameter1
instructionC parameter1, parameter2, parameter3

Засега няма проблем. Но езикът поддържа и макроси:

Define MacroX { foo, bar }
instructionD parameter1, MacroX, parameter4

Define MacroY(macroParameter1, macroParameter2) {
  instructionE parameter1, macroParameter1
  instructionF macroParameter2, MacroX
}

instructionG parameter1, MacroX
MacroY

Разбира се, мога да дефинирам граматика за идентифициране на макроси и препратки към макроси. Но в този случай не знам как бих анализирал съдържанието на макрос, защото не е ясно какво съдържа макросът. Може да бъде само един параметър (това е най-лесно), но може също да бъде няколко параметъра в един макрос (като MacroX в моя пример, който представлява два параметъра) или цял блок от инструкции (като MacroY). И макросите могат дори да съдържат други макроси. Как да поставя това в граматика, ако не е ясно какво е семантично макросът?

Най-лесният подход изглежда е първо да стартирате препроцесор, който да замени всички макроси и едва след това да стартирате анализатора. Но в този случай номерата на редовете се объркват. Искам анализаторът да генерира съобщения за грешка, съдържащи номера на реда, ако има грешка при анализ. И ако предварително обработя входа, номерата на редовете вече не съответстват.

Помощта е много ценена.


person travelboy    schedule 12.09.2011    source източник
comment
Re: редовете се объркват: След като прочетете дефиниция на макрос, можете да изведете еквивалентен брой празни редове или можете да изведете нещо като #line N и да добавите правило към вашия анализатор, което #line N променя текущия номер на ред на N. (Ето как GCC и повечето C препроцесори се справят с #include директиви.)   -  person Chris Lutz    schedule 12.09.2011


Отговори (3)


Макро процесорите са склонни да не зачитат границите на езиковите елементи; по същество те (често) могат да правят произволни промени в привидния входен низ.

Ако случаят е такъв, нямате голям избор: ще трябва да изградите макро процесор, който може да запази номерата на редовете.

Ако макросите винаги съдържат добре структурирани езикови елементи и винаги се срещат на структурирани места в кода, тогава можете да добавите идеята за дефиниция на макрос и извикване към вашата граматика. Това може да направи вашите анализи двусмислени; foo(x) в C кода може да е макро извикване или може да е извикване на функция. Ще трябва някак да разрешите тази неяснота. C анализаторите, използвани за решаване на такива проблеми с двусмислието чрез събиране на информация от символна таблица, докато анализират; ако събирате is-foo-a-macro, докато анализирате, тогава можете да определите дали foo(x) е макро извикване или не.

person Ira Baxter    schedule 12.09.2011

С PEG трябва ръчно да дефинирате местата, където можете да проверявате за макро разширения. Можете да добавите вашия макрос към хеш и да го проверите в PEG правилото(ята), което позволява макроси (infix expr, postfix expr, unop, binop, извикване на функция, ...). Не е толкова лесно, колкото в lisp, но много по-лесно, отколкото с YACC и неговите хакове за приоритет на оператора :)

Други известни PEG рамки, които позволяват макроси, като parrot, perl6, katahdin или PFront, използват трика, за да изпълнят анализа по време на изпълнение, като по този начин търгуват срещу производителността. Или можете да направите и двете и да разрешите предварително компилиран и интерпретиран анализ на PEG. Има няколко проекта, които са мислили за това, но имате нужда от бърза виртуална машина, като luajit, java, clr или приятели.

Използвам специални блокови ключови думи за синтаксис, за да заредя външни споделени библиотеки с външния предварително компилиран PEG анализатор. напр. за анализиране на SQL или FFI декларации във вашия AST. Но можете също да изисквате C компилатор и да компилирате анализа по време на изпълнение за всички макроси.

person rurban    schedule 14.12.2015

С PEG е значително по-лесно, отколкото с всичко друго. На първо място, базираните на Packrat анализатори и други подобни са разширяеми. Вашата дефиниция на макрос може да промени синтаксиса, така че следващия път, когато се използва, тя ще бъде анализирана естествено. Вижте тук и тук някои екстремни примери за този подход.

Друга възможност е да се свържат синтаксични анализатори, което също е тривиално с подходи, базирани на PEG.

person SK-logic    schedule 12.09.2011