Как преобразовать вызовы методов в постфиксную запись?

Я пишу компилятор для языка, похожего на javascript, для развлечения. ака я изучаю колесо, поэтому я делаю его для себя и пытаюсь узнать все, но теперь я застрял.

Я знаю, что алгоритм маневровой станции хорош при разборе простых инфиксных выражений. Мне удалось выяснить, как расширить этот алгоритм для префиксных и постфиксных операторов, а также разобрать простые функции.

Например: 2+3*a(3,5)+b(3,5) превращается в 2 3 <G> 3 5 a () * + <G> 3 5 b () +

(<G> — это защитный токен, который помещается в стек, в нем будет храниться адрес возврата и т. д. () — это команда вызова, которая вызывает функцию на вершине стека, которая выталкивает необходимое количество аргументов и отталкивает результат при возврате. .)

Если имя функции представляет собой всего лишь один токен, я могу просто пометить его как символ функции, если за ним непосредственно следует скобка. Если во время процесса я сталкиваюсь с символом функции, я помещаю его в стек операторов и извлекаю, когда закончу преобразование параметров.

Это работает до сих пор.

Но если я добавлю возможность иметь функции-члены, оператор .. Все становится сложнее. Например, я хочу преобразовать a.b.c(12)+d.e.f(34). Я не могу пометить c и f как функции, потому что a.b.c и d.e.f являются функциями. Если я начну синтаксический анализатор с такого выражения, результат будет a b . <G> 12 c () . d e . <G> 34 f () ., что явно неверно. Я хочу, чтобы это было <G> 12 a b . c . () <G> 34 d e . f. (), что кажется правильным. Но, черт возьми, я могу все усложнить, если добавлю скобки: (a.b.c)(). Или я создаю функцию, которая возвращает функцию, которую я снова вызываю: f(a,b)(c,d).

Есть ли простой способ справиться с этими сложными ситуациями?


person Calmarius    schedule 11.12.2010    source источник


Ответы (2)


Проблема вашего подхода заключается в том, что вы рассматриваете объект и его член как два отдельных токена, разделенных .. Алгоритм классической маневровой станции ничего не знает об ООП и полагается на один токен для вызова функции. Таким образом, первый способ решить вашу проблему - использовать один токен для вызова члена объекта, т.е. весь a.b.c должен быть одним токеном.

Вы также можете обратиться к автоматическим генераторам парсеров для другого решения вашей проблемы. Они позволяют определить полную грамматику вашего целевого языка (JavaScript) как набор формальных правил и автоматически генерировать синтаксический анализатор. Список популярных инструментов включает инструменты, генерирующие парсеры на разных языках программирования: ANTLR, Bison + Lex, Lemon + Ragel .


--артем

person Artem Zankovich    schedule 14.01.2011
comment
. является таким же токеном оператора, как и +. - person ; 14.01.2011
comment
@delnan прав. Мы должны обращаться с точкой так же, как с обычным оператором. - person Mahdi; 04.12.2017

(Я видел, что этот вопрос все еще жив. Я сам нашел для него решение.)

Сначала я угрожаю выражениям (...) и [...] как одному токену и расширяю их (рекурсивно) по мере необходимости. Затем я обнаруживаю вызовы функций и индексы массива. Если перед токеном в скобках нет инфиксного оператора, то это вызов функции или индекс массива, поэтому я вставляю туда специальную функцию вызова или оператор доступа. С этой модификацией он работает как шарм.

person Calmarius    schedule 05.03.2011