В текстовом файле записана (без ошибок) некоторая программа на языке C (или Паскаль, по выбору). Напечатать в алфавитном порядке все различные введенные программистом идентификаторы этой программы, указав для каждого из них в возрастающем порядке номера строк текста, в которых он встречается, а также его тип. Учесть, что в идентификаторах одноименные прописные и строчные буквы отождествляются (или нет, опционально), что внутри литерных значений, строк — констант комментариев последовательности из букв и цифр не являются идентификаторами и что в записи вещественных чисел может встретиться буква Е или е.
Для хранения идентификаторов и номеров строк используйте деревья.
Здравствуйте, std_out, Вы писали:
>> Такая задачка решается парсингом. _>Это я помню, но вот как именно ... _>Увы, за давностью лет позабыл ;( _>Какой метод тут ?
_>Это что же, мне придется грамматику для разбираемого языка написать ?
Здравствуйте, std_out, Вы писали:
_>В текстовом файле записана (без ошибок) некоторая программа на языке C (или Паскаль, по выбору). Напечатать в алфавитном порядке все различные введенные программистом идентификаторы этой программы, указав для каждого из них в возрастающем порядке номера строк текста, в которых он встречается, а также его тип. Учесть, что в идентификаторах одноименные прописные и строчные буквы отождествляются (или нет, опционально), что внутри литерных значений, строк — констант комментариев последовательности из букв и цифр не являются идентификаторами и что в записи вещественных чисел может встретиться буква Е или е. _>Для хранения идентификаторов и номеров строк используйте деревья.
1) Выбираем тул для генерации парсера с прицелом на то, чтобы найти под него уже написанную грамматику Си. Выше предлагали antlr, (устаревшей) классикой является сочетание flex + yacc (можете в драгон буке подсмотреть использование этой связки). Можете у gcc фронтенд отрезать, если осилите
2) Если получаете LR или LRLA грамматику, в действиях свертки соотв-го нетерминала у вас под рукой будут и имя переменной и ее тип.
3) Генерите парсер.
Здравствуйте, gh2, Вы писали:
gh2>Здравствуйте, std_out, Вы писали:
_>>В текстовом файле записана (без ошибок) некоторая программа на языке C (или Паскаль, по выбору). Напечатать в алфавитном порядке все различные введенные программистом идентификаторы этой программы, указав для каждого из них в возрастающем порядке номера строк текста, в которых он встречается, а также его тип. Учесть, что в идентификаторах одноименные прописные и строчные буквы отождествляются (или нет, опционально), что внутри литерных значений, строк — констант комментариев последовательности из букв и цифр не являются идентификаторами и что в записи вещественных чисел может встретиться буква Е или е. _>>Для хранения идентификаторов и номеров строк используйте деревья.
gh2>1) Выбираем тул для генерации парсера с прицелом на то, чтобы найти под него уже написанную грамматику Си. Выше предлагали antlr, (устаревшей) классикой является сочетание flex + yacc (можете в драгон буке подсмотреть использование этой связки). Можете у gcc фронтенд отрезать, если осилите gh2>2) Если получаете LR или LRLA грамматику, в действиях свертки соотв-го нетерминала у вас под рукой будут и имя переменной и ее тип. gh2>3) Генерите парсер.
Кстати — если говорить о C, то существует, как минимум, одно осложнение, связанное с макросами и include'ами. Считать ли переменные, определенные посредством этих механизмов "введенными программистом"?
Здравствуйте, 31415926, Вы писали:
3>Кстати — если говорить о C, то существует, как минимум, одно осложнение, связанное с макросами и include'ами. Считать ли переменные, определенные посредством этих механизмов "введенными программистом"?
Наверное об этом нужно спросить автора задачи, IMHO скорее всего она чисто академическая, и исходники не подвергаются препроцессингу и не предполагают успешности линковки. В любом случае, есть разумные стратегии для решения задачи с препроцессингом (не составит труда ввести в грамматику синтезируемый атрибут, устанавливаемый при раскрытии, например, макроса) и без (очевидно).
Здравствуйте, std_out, Вы писали:
_>Это что же, мне придется грамматику для разбираемого языка написать ?
По-моему, тут будет достаточно лексического анализа, причем очень примитивного (потому что нас интересуют только две лексемы — "идентификатор" и "не идентификатор", а текст разбираемой программы гарантированно корректный). Можно сделать на коленке, без применения научных подходов. Просто нарисовать конечный автомат на бумажке и захардкодить.
Здравствуйте, std_out, Вы писали:
_>В текстовом файле записана (без ошибок) некоторая программа на языке C (или Паскаль, по выбору). Напечатать в алфавитном порядке все различные введенные программистом идентификаторы этой программы, указав для каждого из них в возрастающем порядке номера строк текста, в которых он встречается, а также его тип. Учесть, что в идентификаторах одноименные прописные и строчные буквы отождествляются (или нет, опционально), что внутри литерных значений, строк — констант комментариев последовательности из букв и цифр не являются идентификаторами и что в записи вещественных чисел может встретиться буква Е или е. _>Для хранения идентификаторов и номеров строк используйте деревья.
ИМХО, можно обойтись без тяжелой артиллерии.
Нас действительно интересуют только два состояния: начался идентификатор, кончился идентификатор. Разделим множество всех символов на три: символы, с которых может начинаться идентификатор, символы, которые могут входить в идентификатор и символы, которые не могут входить в идентификатор.
При обнаружении символа, начинающего идентификатор, начинаем прицеплять символы к строке до первого символа, который входить не может.
Но потом набранный ид-р нужно сравнить с ключевыми словами.
Правда, если нужно учитывать вложенность, то я б выбрал паскаль — там процедуры и функции объявляются с помощью ключевого слова.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, LaptevVV, Вы писали:
LVV>Но потом набранный ид-р нужно сравнить с ключевыми словами. LVV>Правда, если нужно учитывать вложенность, то я б выбрал паскаль — там процедуры и функции объявляются с помощью ключевого слова.
Не получится без тяжелой артилерии.
int (*foo)(const struct* boo);
По условию задачи тип int (*)(const struct* boo) надо вытащить.
Здравствуйте, maykie, Вы писали:
M>Здравствуйте, LaptevVV, Вы писали:
LVV>>Но потом набранный ид-р нужно сравнить с ключевыми словами. LVV>>Правда, если нужно учитывать вложенность, то я б выбрал паскаль — там процедуры и функции объявляются с помощью ключевого слова. M>Не получится без тяжелой артилерии. M>
M>int (*foo)(const struct* boo);
M>
M>По условию задачи тип int (*)(const struct* boo) надо вытащить.
Именно поэтому поиск в паскале проще — там ключевые слова есть procedure и function
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, maykie, Вы писали:
M>По условию задачи тип int (*)(const struct* boo) надо вытащить.
а ещё ведь и typedefs бывают...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском