Для общего развития, никогда не помешает написать компилятор языка. Я не ставлю перед собой задачу написать компилятор c++ или c#, задачу которую я перед собой ставлю - это необходимый минимум для ознакомления с теорией компиляции.
Входной язык будет достаточно простой, урезанный по самое не могу, C. А выходной язык будет - язык Ассемблера.
Суть компиляции заключается в переводе одного языка в другой, я бы назвал это трансляцией или просто переводом. То есть компилятор не исполняет код, а он его переводит.
Наш простейший компилятор языка C (далее TheSimpliestCCompiler - tsico), будет разбит на четыре блока или более: transliteration unit, lexical unit, syntax unit, generation unit. Получатся четырех-проходной компилятор. Чем же занимаются эти блоки?
Transliteration Unit
Суть транслитерация заключается вот в чем, транслитератору на вход подается цепочка символов, а он сопоставляет их с символьными классами, если символ принадлежит неизвестному ранее классу символов, то мы его пропускаем и записываем ошибку в журнал, мол встретился такой-то неожиданный символ.
В случае программы, это будет звучат так, транслитератор считывает файл с исходным кодом "посимвольно", определяет класс символа и записывает в выходной файл, символ с названием сопоставленного с ним класса.
Lexical Unit
Лексический блок используя конечные автоматы обрабатывает символы с их символьными классами и на выходе отдает набор уже лексем.
Syntax Unit
Получает набор лексем, проверяет синтаксис. Определяет набор атомов(простейших единичных
конструкций языка).
Generation Unit
Получает набор атомов и по ним строит программу на выходному языке. Это достаточно простой блок.
Транслитератор
Сегодня, мы приступим к транслитератору. Сразу оговорюсь, язык на котором, мы будем писать транслитератор - C#.
Итак, еще раз суть транслитератора заключается в сопоставлении символов с их символьными классами. Мы пройдемся по файлу исходного кода, после чего на выходе получим файл удобный для чтения лексическим блоком, а также запишем встретившиеся ошибки в журнал ошибок.
Определимся с символьными классами для простейшего прототипа языка C:
- letter - [A-Za-z]
- digit - [0-9]
- whitespace - ' '
- newline - '\n'
- compare - [><=!]
- arithmetic - [+-/*]
- ( - '('
- ) - ')'
- ; - ';'
- { - '{'
- } - '}'
- . - '.'
- : - ':'
Символы, которые не вошли в данный перечень отнесем к классу other.
Я не буду приводить весь код транслитератор. Покажу лишь фрагмент:
class TransliterationUnit
{
// ...
public void Transliterate(
string input, string output)
{
// don't do this at production,
// reading string to memory can be
// so dangerous on files with larger size
string code = File.OpenText(input).ReadToEnd().
Replace("\r", "").
Replace("\t", "").Trim().
ClearExtraWhitespaces();
List<Symbol> symbols = new List<Symbol>();
foreach (char c in code)
{
if (GetSymbolClass(c) != "other")
{
symbols.Add(new Symbol() {
Value = c,
Class = GetSymbolClass(c)});
}
else
{
_logger.Log(String.Format(
"Unexpected symbol - '{0}'", c));
}
}
SaveSymbols(output, symbols);
}
// ...
}
Если у вас есть желание ознакомиться с полной работающей версии транслитератора компилятора tsico (я упоминал о названии выше), то вы можете скачать проект с исходным кодом для Visual Studio 2010.
Литература
В завершение я бы хотел посоветовать вам книгу "Альфред В. Ахо, Моника С. Лам, Рави Сети, Джеффри Д. Ульман: Компиляторы. Принципы, технологии и инструментарий".
Комментариев нет:
Отправить комментарий