Почему макросы, основанные на абстрактных синтаксических деревьях, лучше, чем макросы, основанные на предварительной обработке строк? - PullRequest
0 голосов
/ 24 мая 2018

Я начинаю свой путь изучения Руста.Я встретил эту строку в Rust by Example :

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

Почему абстрактное синтаксическое дерево лучше, чем предварительная обработка строки?

Ответы [ 2 ]

0 голосов
/ 24 мая 2018

Если у вас есть это в C:

#define X(A,B) A+B
int r = X(1,2) * 3;

Значение r будет 7, потому что препроцессор расширяет его до 1+2 * 3, то есть 1+(2*3).

В Rust вы получите:

macro_rules! X { ($a:expr,$b:expr) => { $a+$b } }
let r = X!(1,2) * 3;

Это будет равно 9, потому что компилятор будет интерпретировать расширение как (1+2)*3.Это связано с тем, что компилятор знает, что результатом макроса считается полное автономное выражение.

При этом макрос C также может быть определен так:

#define X(A,B) ((A)+(B))

Это позволило бы избежать каких-либо неочевидных проблем с оценкой, в том числе самих аргументов, интерпретируемых по-разному из-за контекста.Однако, когда вы используете макрос, вы никогда не можете быть уверены, правильно ли макрос учел все возможные способы его использования, поэтому трудно сказать, что будет делать любое данное расширение макроса.

Используя узлы AST вместо текста, Rust гарантирует, что эта двусмысленность не произойдет.

0 голосов
/ 24 мая 2018

Классический пример использования препроцессора C:

#define MUL(a, b) a * b

// ...

int res = MUL(x + y, 5);

Использование макроса расширится до

int res = x + y * 5;

, что очень далеко от ожидаемого

int res = (x + y) * 5;

Это происходит потому, что препроцессор C в действительности просто выполняет простые текстовые подстановки, на самом деле он не является неотъемлемой частью самого языка.Предварительная обработка и синтаксический анализ - это два отдельных шага.

Если препроцессор вместо этого проанализировал макрос, как и остальная часть компилятора, что происходит для языков, где макросы являются частью фактического синтаксиса языка, это больше не проблема, так каккак приоритет (как упомянуто) и ассоциативность приняты во внимание.

...