Это самая простая часть imo, когда у вас работает парсер, когда вы сталкиваетесь с идентификаторами в вашей грамматике, у вас уже есть каждый бит информации о них, типа, если они являются частью правила грамматики функции или нет, и если они являются частью объявления / определения функции, у вас есть каждый параметр с их типами.
Как только вы идентифицируете всю эту информацию, самая основная таблица символов (только глобальные) состоит в том, чтобы создать список союзов либо имени и типа (переменная), либо имени, типа и списка типа имени комбо (функция). Вы можете отделить их с помощью флага или чего-то еще. Как только это будет сделано, вы можете вложить его в функции и в область видимости, создав, таким образом, таблицу символов в стиле c. В конце, на этапе генерации кода, именно здесь вы собираетесь написать регистры / метки, которые будут использовать ваши символы, поэтому убедитесь, что они легко расширяемы; ты много вернешься в этот репозиторий, чтобы добавить бухгалтерские данные.
Самая хитрая часть - это перенос информации, когда вы все еще анализируете свою грамматику. Обычно это делается с большой структурой, которую вы заполняете при прочтении. Возьмите объявление int f(int x, int y)
в стиле C: когда вы анализируете int f
, вы еще не знаете, анализируете ли вы функцию или переменную, поэтому вам нужно заполнить структуру только именем и типом, а затем передать это до более низких узлов дерева (в случае парсера рекурсивного спуска) и позволяет им иметь дело с этим, затем, как только они будут сделаны, верните структуру вызывающей стороне, чтобы они имели полную информацию, даже если вы, в конкретные функции, понятия не имею, что это за разбор.