Здравствуйте, VVVa, Вы писали:
VVV>Вопрос в следующем — на каком этапе компиляции узнаётся name? VVV>при LR парсинге или после него ? тогда как парсить не зная структуры програмы?
Ну, грубо говоря, в тот момент, когда лексер вычитает очередной идентификатор, компилятор поищет его сначала в таблице символов, а потом в таблице типов. И в зависимости от того, найдет ли, поступит по-разному.
Здравствуйте, VVVa, Вы писали:
VVV>при LR парсинге или после него ? тогда как парсить не зная структуры програмы?
А вы не пробывали начать с чего-нибудь попроще?
Здравствуйте, Pzz, Вы писали:
Pzz>Ну, грубо говоря, в тот момент, когда лексер вычитает очередной идентификатор, компилятор поищет его сначала в таблице символов, а потом в таблице типов. И в зависимости от того, найдет ли, поступит по-разному.
золотые слава! но наверное он только типы подставляет (с переменными надо учитывать структуру кода).
Здравствуйте, VVVa, Вы писали:
Pzz>>Ну, грубо говоря, в тот момент, когда лексер вычитает очередной идентификатор, компилятор поищет его сначала в таблице символов, а потом в таблице типов. И в зависимости от того, найдет ли, поступит по-разному.
VVV>золотые слава! но наверное он только типы подставляет (с переменными надо учитывать структуру кода).
Нет, в твоем примере компилятор видит умножение, найдя известную ему к этому моменту переменную name.
Здравствуйте, VVVa, Вы писали:
Pzz>>Нет, в твоем примере компилятор видит умножение, найдя известную ему к этому моменту переменную name.
VVV>Блин действительно ... А как тогда он проверяет облости видимости переменных ? ведь дерево ещё не построено ...
Так и проверяет. Появилось объявление переменной — добавили. Типа — добавили. Видим идентификатор — пытаемся по тому, в какой он таблице, определить его роль.
Закончился блок — почистили таблицы и пошли дальше.
У тебя ещё много открытий впереди C ещё относительно прост в этом смысле.
C++ — вот как насчёт такого (вторая часть комментария)?
Пока класс целиком не распарсен, нельзя делать предположения о смысле некоторых грамматических конструкций внутри его определения. А после ещё чудесатее:
До этапа кодогенерации ещё дожить надо — а вы пока не рассказали, как вы AST строить собрались, если для синтаксического разбора нужно уметь решать уравнения на эллиптических кривых — причём со входными данными, приходящими от целевой платформы.
Не забудьте, что там вместо банального sizeof может стоять вызов любой constexpr функции, а дальнейшее дерево зависит от результата вычислений оной функции.
Мнэээ, гражданин... не советую. Съедят.
После такого — всех калёной метлой гнать в сторону LISP. Ну ладно, Go или Pascal.
Здравствуйте, kov_serg, Вы писали:
_>Здравствуйте, VVVa, Вы писали:
VVV>>при LR парсинге или после него ? тогда как парсить не зная структуры програмы? _>А вы не пробывали начать с чего-нибудь попроще?
Forth слишком просто. Как и LISP во всех его видах.
Pascal, или лучше Modula — вот самое удобное для тренировок.
Правда, после этого явно не захочется идти даже к C, не говоря про C++.
Здравствуйте, VVVa, Вы писали:
Pzz>>Нет, в твоем примере компилятор видит умножение, найдя известную ему к этому моменту переменную name.
VVV>Блин действительно ... А как тогда он проверяет облости видимости переменных ? ведь дерево ещё не построено ...
Он добавляет их в дерево по одной, по мере продвижения по исходнику.
Гораздо интереснее, как это делает компилятор C++. Он позволяет ссылаться на имена членов классов, которые описаны дальше по коду.
Здравствуйте, netch80, Вы писали:
N>Так и проверяет. Появилось объявление переменной — добавили. Типа — добавили. Видим идентификатор — пытаемся по тому, в какой он таблице, определить его роль. N>Закончился блок — почистили таблицы и пошли дальше.
Еле догнал если токен "int x;" свернулся парсером то заводим переменную и помечаем где она стоит... А потом если есть свёртка с элементом "int x;" то удаляем
N>У тебя ещё много открытий впереди C ещё относительно прост в этом смысле.
а какие открытия может подскажите? именно для С N>C++ — вот как насчёт такого (вторая часть комментария)?
Жалко до кодогенерации не дошёл не совсем понял тяжесть происходящего N>Пока класс целиком не распарсен, нельзя делать предположения о смысле некоторых грамматических конструкций внутри его определения. А после ещё чудесатее:
N>
До этапа кодогенерации ещё дожить надо — а вы пока не рассказали, как вы AST строить собрались, если для синтаксического разбора нужно уметь решать уравнения на эллиптических кривых — причём со входными данными, приходящими от целевой платформы.
N>Не забудьте, что там вместо банального sizeof может стоять вызов любой constexpr функции, а дальнейшее дерево зависит от результата вычислений оной функции.
"на эллиптических кривых" — Вы пошутили? причём тут криптография?
Ну в курсе что в sizeof может стоять выражение — тогда размер это размер от получаемого типа. Или Вы не про это?
Ну я AST на списках наверное буду делать ... но как его обходить покуда не знаю ... может Матрицу смежности или Матрицу инцидентности придётся применять...
N>Мнэээ, гражданин... не советую. Съедят.
А вдруг весело будет ... N>После такого — всех калёной метлой гнать в сторону LISP. Ну ладно, Go или Pascal.
Здравствуйте, VVVa, Вы писали:
N>>Так и проверяет. Появилось объявление переменной — добавили. Типа — добавили. Видим идентификатор — пытаемся по тому, в какой он таблице, определить его роль. N>>Закончился блок — почистили таблицы и пошли дальше.
VVV>Еле догнал если токен "int x;" свернулся парсером то заводим переменную и помечаем где она стоит... А потом если есть свёртка с элементом "int x;" то удаляем
а, где-то так.
VVV>а какие открытия может подскажите? именно для С
В C, наверно, самое путаное это логика препроцессора — все эти когда что раскрывается и с чем объединяется. После этого — лукап по таблицам, это переменная, тип или что-то другое, как тут описывали.
Но я не вижу глубинного смысла ограничиваться C.
VVV>"на эллиптических кривых" — Вы пошутили? причём тут криптография?
1. Не я, а автор комментария на хабре.
2. Не пошутил. Язык шаблонов C++ тьюринг-полный и в нём можно задать какие угодно работы, причём часть обработки идёт косвенно (по сути, компилятор решает заданное в виде уравнений).
Другой вопрос, что компилятор, скорее всего, имеет жёсткие ограничения на размер этой работы.
VVV>Ну я AST на списках наверное буду делать ... но как его обходить покуда не знаю ... может Матрицу смежности или Матрицу инцидентности придётся применять...
Почему на списках?
N>>Мнэээ, гражданин... не советую. Съедят. VVV>А вдруг весело будет ...
"Странные праздники... Знобит меня от этого веселья." (c)
N>В C, наверно, самое путаное это логика препроцессора — все эти когда что раскрывается и с чем объединяется. После этого — лукап по таблицам, это переменная, тип или что-то другое, как тут описывали.
а препроцессор тоже в объединён с парсером?
N>Но я не вижу глубинного смысла ограничиваться C.
но ведь написать С полегче чем С++
N>Почему на списках?
ну так легче дочерние элементы хранить и под дебагером виднее
Здравствуйте, VVVa, Вы писали:
VVV>Еле догнал если токен "int x;" свернулся парсером то
"int x;" — не токен, а три токена: "int", "x" и ";". У первого например тип — "ключевое слово", у второго — "идентификатор", у третьего — "разделитель".
VVV>Ну я AST на списках наверное буду делать ... но как его обходить покуда не знаю ...
Два основных метода обхода графов и деревьев, которые есть частный случай графов, существуют:
1. Поиск в глубину (Depth First Search or DFS)
2. Поиск в ширину (Breadth First Search or BFS)
VVV>может Матрицу смежности или Матрицу инцидентности придётся применять...
Не надо вам эти матрицы. Их используют, когда заранее известен размер графа, или для плотных графов. У вас дерево строится динамически, его размер заранее неизвестен. Не будете же вы перестраивать матрицу при каждом чихе.
Сначала строить AST без парсинга тел методов (можно на уровне валидации пропарсить — проверить, что там нет однозначного неверного кода). Составить всякие словари типов и тд. И потом уже тела методов окончательно пропарсить.
Здравствуйте, vsb, Вы писали:
vsb>Сначала строить AST без парсинга тел методов (можно на уровне валидации пропарсить — проверить, что там нет однозначного неверного кода). Составить всякие словари типов и тд. И потом уже тела методов окончательно пропарсить.
Интересный вопрос возник как Вы так парсите сначала без методов потом с ними?
Вы какимто поиском пользуетесь? но в LR вроде его нету...
Здравствуйте, VVVa, Вы писали:
VVV>Интересный вопрос возник как Вы так парсите сначала без методов потом с ними? VVV>Вы какимто поиском пользуетесь? но в LR вроде его нету...
Так а кто говорит конкретно про LR, LL или что-то подобное? Они все как-то не очень соответствуют реалиям таких языков. Иначе бы не писали рукопашные парсеры, а пользовались генераторами вроде YACC или ANTLR.
Здравствуйте, VVVa, Вы писали:
N>>В C, наверно, самое путаное это логика препроцессора — все эти когда что раскрывается и с чем объединяется. После этого — лукап по таблицам, это переменная, тип или что-то другое, как тут описывали. VVV>а препроцессор тоже в объединён с парсером?
С обоими, лексером и парсером.
На выходе препроцессора, формально, поток лексем. Но как минимум #line и #pragma требуют поддержки в парсере.
N>>Но я не вижу глубинного смысла ограничиваться C. VVV>но ведь написать С полегче чем С++
Написать — да. Но зачем? Если это реальная заказная работа, то ограничиваться C нет смысла, а если это для себя, то вообще к ним лезть не следует, ибо бесполезный гимор.
VVV>А Вы С++ компилятор писали?
Нет. У меня нет даже 10 человеко-лет ненужных, чтобы выкинуть их на повторение уже доступных GCC или Clang в худшем варианте.