Команды препроцессора в C считаются токенами? - PullRequest
0 голосов
/ 23 сентября 2018

Я читал о токенах и подсчитывал количество токенов в программе.

Ранее я где-то читал, что команды препроцессора не считаются токенами.Но когда я читаю о токенах на Geeksforgeeks , они приводятся в разделе «специальные символы»:

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

Поэтому я запутался, что в программе, если мы напишем #define, это будет токен?

Например:

#include<stdio.h> 
#define max 100 
int main() 
{ 
    printf("max is %d", max); 
    return 0; 
} 

Сколько токенов в этом примере .?

1 Ответ

0 голосов
/ 23 сентября 2018

Связанная статья полна основных ошибок, и на нее не следует полагаться.

Процесс синтаксического анализа C или C ++ определяется как последовательность преобразований: 1

  1. Обратная косая черта - новая строка заменяется ничем - даже пробелом.
  2. Комментарии удаляются и заменяются одним пробелом.
  3. Оставшийся в живых текст преобразуется всерия токенов предварительной обработки .Они менее специфичны, чем токены, используемые самим языком: например, ключевое слово if является токеном IF для самого языка, но является просто токеном IDENT препроцессору.
  4. Выполняются директивы предварительной обработки имакросы раскрываются.
  5. Каждый токен предварительной обработки преобразуется в токен.
  6. поток токенов анализируется в абстрактном синтаксическом дереве, а остальная часть компилятора берет его оттуда.

Ваша программа-пример

#include<stdio.h> 
#define max 100 
int main() 
{ 
    printf("max is %d", max); 
    return 0; 
}

после преобразования 3 будет представлять собой серию из 23 токенов предварительной обработки:

PUNCT:# IDENT:include INCLUDE-ARG:<stdio.h>
PUNCT:# IDENT:define IDENT:max PP-NUMBER:100
IDENT:int IDENT:main PUNCT:( PUNCT:)
PUNCT:{
IDENT:printf PUNCT:( STRING:"max is %d" PUNCT:, IDENT:max PUNCT:) PUNCT:;
IDENT:return PP-NUMBER:0 PUNCT:;
PUNCT:}

На этом этапе все еще присутствуют директивы,Обратите внимание, что #include и #define - это каждый два токена: # и имя директивы являются отдельными.Некоторым людям нравится писать сложные #if гнезда с хеш-метками, все в столбце 1, но имена директив с отступом.

После преобразования 5 директивы исчезли, и у нас есть 16 + n токенов этой серии:

[ ... some large volume of tokens produced from the contents of stdio.h ... ]
INT IDENT:main LPAREN RPAREN
LBRACE
IDENT:printf LPAREN STRING:"max is %d" COMMA DECIMAL-INTEGER:100 RPAREN SEMICOLON
RETURN DECIMAL-INTEGER:0 SEMICOLON
RBRACE

, где 'n' равно количеству токенов, полученных из stdio.h.

Директивы предварительной обработки (#include, #define, #if и т. Д.) всегда удаляются из потока токенов и, возможно, заменяются чем-то другим, так что после преобразования 6 у вас никогда не будет токенов, которые являются прямым результатом текста директивной строки.Но у вас обычно будут токены, которые являются результатом эффектов каждой директивы, таких как содержимое stdio.h и DECIMAL-INTEGER:100, заменяющих IDENT:max.

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


1 Иногда вы увидите, как люди говорят о фазах перевода , именно так стандарты C и C ++ официально описывают эту серию операций.Мой список не список этапов перевода;он включает отдельные пункты для некоторых вещей, которые по стандартам сгруппированы в одну фазу, и пропускает несколько шагов, не относящихся к данному обсуждению.

...