Как escape-последовательности с обратной косой чертой реализованы в компиляторах? - PullRequest
5 голосов
/ 26 декабря 2011

Я просто хотел узнать, как escape-последовательности обратной косой черты реализованы в компиляторах?Если мы напишем «\ n» в строке, как компилятор заменит его символом новой строки?Как компилятор заменяет "\ b" символом возврата на одну позицию?

Я спрашиваю, потому что написал код:

#include<stdio.h>
main()
{
    printf("Hello \c");
}

Вывод был:

Hello 
Exited: ExitFailure 7 

Я запустил его в кодовом блоке, я просматривал вопрос о книге KnR 1.2.

Заранее спасибо

Ответы [ 3 ]

8 голосов
/ 26 декабря 2011

Чтобы понять это, вы должны немного понять, как работают компиляторы в целом.Первый шаг, который обычно предпринимают компиляторы, называется лексическим анализом (или лексизмом для краткости).Лексический анализ - это когда компилятор берет входной код и разбивает его на части, которые он может распознать.Для этого обычно используются регулярные выражения для распознавания различных частей.Один из фрагментов, которые он распознает, - строковый литерал, представляющий собой строку в кавычках, например "Hello".Регулярное выражение для строкового литерала обычно выглядит как "([^\"]|\"|\\|\n|\b)*".Что на английском языке означает список символов, который начинается с двойной кавычки и заканчивается двойной кавычкой, а между ними есть либо 1) любой символ, который не является двойной кавычкой или обратной косой чертой 2) обратный слеш, а затем двойнаяцитата 3) обратная косая черта, а затем еще одна обратная косая черта 4) обратная косая черта и затем n 5) обратная косая черта и затем a b.Этот средний шаблон повторяется ноль или более раз.(Примечание: в реальных компиляторах список символов, которые могут появляться после обратной косой черты, обычно длиннее).Поиск этого шаблона позволяет ему находить строковые литералы.

Затем, после того как строковый литерал был идентифицирован, чтобы выяснить, какую строку фактически поместить в память, он должен выполнить второй уровень обработки, который долженпройти через строковый литерал и обработать обратную косую черту.Он просто читает от начала до конца, ища последовательности с обратной косой чертой.Каждая из последовательностей обратной косой черты заменяется другим символом.\" становится ".\\ становится \.\n становится новой строкой.\b становится символом возврата и т. Д.Чтобы выяснить, куда и куда поместить, он просто использует таблицу, которая показывает, что нужно разместить для этой последовательности.

5 голосов
/ 26 декабря 2011

Классическое объяснение дано в известной статье Кена Томпсона под названием «Размышления о доверии» (также доступно из многих других источников , включая книга Лекции Премии Тьюринга ACM: первые двадцать лет 1966-1985 ), которые были его благодарственной речью, когда он получил Премию Тьюринга ACM вместе с Деннисом Ричи.

Среди прочего, он описывает, как добавить \v к компилятору, который его не распознает:

C позволяет строковой конструкции указывать инициализированный массив символов. Отдельные символы в строке могут быть экранированы для представления непечатные символы. Например,

"Hello world\n"

представляет строку с символом "\n", представляющую новую строку характер.

Рисунок 2.1 - идеализация кода в компиляторе C, который интерпретирует escape-последовательность символов Это удивительный кусок код. Он «знает» полностью переносимым образом, что такое код символа скомпилировано для новой строки в любом наборе символов. Акт познания тогда позволяет ему перекомпилировать себя, тем самым увековечивая знания.

Предположим, мы хотим изменить компилятор C, чтобы включить последовательность "\v" в представляет символ вертикальной табуляции. Расширение к рисунку 2.1 очевидно и представлено на рисунке 2.2. Затем мы перекомпилируем C компилятор, но мы получаем диагностику. Очевидно, что поскольку бинарная версия компилятора не знает о "\v", источник не является легальным C. Мы должен "обучить" компилятор. После того, как он «знает», что означает «\v», наш новое изменение станет законным C. Мы смотрим на график ASCII, что вертикальная табуляция десятичная 11. Мы изменяем наш источник, чтобы он выглядел как рисунок 2,3. Теперь старый компилятор принимает новый источник. Мы устанавливаем получившийся двоичный файл в качестве нового официального компилятора C, и теперь мы можем написать портативная версия, как у нас на рисунке 2.2.

Это глубокая концепция. Это так же близко к программе обучения, как и я видел. Вы просто скажете это один раз, тогда вы можете использовать это самореферентное определение.

Рисунок 2.1

c = next();
if (c != '\\')
    return(c);
c = next();
if (c == '\\')
    return('\\');
if (c == 'n')
    return('\n');

Рисунок 2.2

c = next();
if (c != '\\')
    return(c);
c = next();
if (c == '\\')
    return('\\');
if (c == 'n')
    return('\n');
if (c == 'v')
    return('\v');

Рисунок 2.3

c = next();
if (c != '\\')
    return(c);
c = next();
if (c == '\\')
    return('\\');
if (c == 'n')
    return('\n');
if (c == 'v')
    return(11);
4 голосов
/ 26 декабря 2011

Вот отличный обзор того, что такое компилятор. В нем перечислены компоненты: Разница между компиляторами и парсерами?

Короткий ответ: компилятор является распознавателем строк. Он видит то, что соответствует правилу (на основе контекста), а затем принимает решение, каким должен быть результат.

Вот связанный пост, и один из постов также рекомендует то, что рекомендовал Джонатан Леффлер. Что за магия скрытого персонажа (\)

Еще один короткий ответ на все вопросы компилятора - грамматика.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...