Espacios de nombres
Variantes

Fases de la traducción

De cppreference.com

El compilador procesa el archivo fuente C++ como si tuvieran lugar las siguientes fases, en este orden exacto:

Fase 1

1) Los bytes individuales del archivo de código fuente se convierten (en la forma que define la implementación) a los caracteres del juego de caracteres fuente básico (hasta C++23)juego de caracteres de traducción (desde C++23). En particular, los finales de línea dependientes del sistema operativo se reemplazan por caracteres de nueva línea.
2) La implementación decide el juego de caracteres del archivo fuente que acepta (desde C++11). Cualquier carácter del archivo funete que no se puede convertir a un carácter del juego de caracteres fuente básico se reemplaza por su nombre de carácter universal (precedido por \u o \U) o por alguna otra forma definida por la implementación que se maneja de forma equivalente. (hasta C++23)
3) Las secuencias de trígrafos se reemplazan por su representación de carácter único correspondiente.
(hasta C++17)

Fase 2

1) Cuando al final de una línea aparece una barra invertida (seguida inmediatamente de cero o más caracteres de espacio en blanco distintos de nueva línea seguido de (desde C++23) el carácter de nueva línea), esos caracteres se eliminan, combinando las dos líneas físicas en una línea lógica. Es una operación de un solo paso: una línea terminada con dos barras invertidas seguidas de una línea vacía no combina tres líneas en una. Si en esta fase se forma un nombre de carácter universal (\uXXXX), el comportamiento no está definido.
2) Si un archivo fuente no vacío no termina con un carácter de nueva línea después de este paso (si originalmente no tenía una nueva línea, o terminaba con una nueva línea inmediatamente precedida por una barra inversa), el comportamiento no está definido (hasta C++11)se añade un carácter de nueva línea (desde C++11).

Fase 3

1) Se descompone el archivo fuente en comentarios, secuencias de caracteres de espacios en blanco (espacio, tabulador horizontal, nueva línea, tabulador vertical, y retorno de carro), y tókenes de preprocesamiento, que son los siguientes:
a) nombres de encabezados como <iostream> o "myfile.h";
c) números de preprocesamiento;
d) Literales de carácter y de cadena , incluyendo literales definidos por usuario (desde C++11);
e) operadores y símbolos de puntuación (incluyendo tókenes alternativos), como +, <<=, <%, ##, o and;
f) caracteres individuales, no espacio en blanco, que no entran en otra categoría.
2) Se deshacen todas las transformaciones realizadas durante las fases 1 y 2 entre las comillas dobles inicial y final de cualquier literal cadena sin formato.
(desde C++11)
3) Cada comentario se sustituye con un carácter de espacio.

Se mantienen las nuevas líneas, y no se especifica si las secuencias de espacios en blanco que no son de nueva línea pueden colapsarse en caracteres de un solo espacio.

A medida que los caracteres del archivo fuente se examinan para conformar el siguiente token de preprocesamiento (es decir, no se analizan como parte de un comentario u otras formas de espacio en blanco), se reconocen los nombres de carácter universal y se reemplazan por el elemento designado del juego de caracteres de traducción, excepto cuando coincide con una secuencia en:

a) un literal de carácter (c-char-sequence);
b) un literal de cadena (s-char-sequence y r-char-sequence), excluyendo los delimitadores (d-char-sequence);
c) un nombre de archivo para inclusión (h-char-sequence y q-char-sequence).
(desde C++23)

Si la entrada se transformó en tókenes de preprocesamiento hasta un carácter dado, generalmente el siguiente token de preprocesamiento se toma como la secuencia más larga de caracteres que puede formar un token de preprocesamiento, incluso si eso causa un error en el análisis posterior. Comúnmente esto se conoce como maximal munch o "mascada máxima" debido a que el preprocesamiento "masca" un número máximo de caracteres de la entrada.

int foo = 1;
int bar = 0xE+foo;   // error, preproceso erróneo de número 0xE+foo
int baz = 0xE + foo; // correcto

int quux = bar+++++baz; // error: bar++ ++ +baz, no bar++ + ++baz.

Las únicas excepciones a la regla maximal munch son:

  • Si el siguiente carácter inicia una secuencia de caracteres que podría ser el prefijo y las comillas dobles iniciales de una literal cadena sin formato, el próximo token de preprocesamiento será un literal de cadena sin formato. El literal consiste en la secuencia de caracteres más corta que cumple el patrón de cadena sin formato.
#define R "x"
const char* s = R"y"; // literal cadena sin formato mal formada, no "x" "y"
const char* s2 = R"(a)" "b)"; // un literal de cadena sin formato seguido 
                              // de un literal de cadena normal
  • Si los siguientes tres caracteres son <:: y el carácter subsiguiente no es : ni >, se trata < como un token de preprocesamiento por sí mismo (y no como el primer carácter del token alternativo <:).
struct Foo { static const int v = 1; };
std::vector<::Foo> x;  // Correcto, <: no se entiende como el token alternativo para [
extern int y<::>;      // Correcto, lo mismo que extern int y[].
int z<:::Foo::value:>; // Correcto, int z[::Foo::value];
(desde C++11)
  • Los tókenes de preprocesamiento de nombres de encabezado solo se forman dentro de una directiva #include
std::vector<int> x; // Correcto, <int> no es el nombre de un encabezado


Fase 4

1) Se ejecuta el preprocesador. Si se forma un nombre de carácter universal debido a la concatenación de token, el comportamiento no está definido. (hasta C++23)
2) Cada archivo insertado con la directiva #include pasa por las fases 1 hasta 4, recursivamente.
3) Al final de esta fase, se eliminan todas las directivas de preprocesador de la fuente.

Fase 5

1) Todos los caracteres literales de carácter y literales cadena se convierten del juego de caracteres de fuente al juego de caracteres de ejecución (que puede ser un juego de caracteres multibyte como UTF-8, siempre y cuando los 96 caracteres del juego básico de caracteres de fuente listados en la fase 1 tengan una representación de un byte).
2) Las secuencias de escape y los nombres universales de carácter en literales de carácter y literales de cadena procesados se expanden y se convierten al juego de caracteres de ejecución. Si el carácter especificado mediante un nombre universal de carácter no es miembro del juego de caracteres de ejecución, el resultado está definido por la implementación, pero se garantiza que no sea un carácter nulo (extenso).

Nota: la conversión realizada en esta etapa se puede controlar en algunas implementaciones mediante opciones de la línea de comandos: gcc y clang usan -finput-charset para especificar la codificación del juego de caracteres del fuente, -fexec-charset y -fwide-exec-charset para especificar la codificación del juego de caracteres de ejecución en literales de carácter y cadena que no tienen un prefijo de codificación (desde C++11), mientras Visual Studio 2015 Update 2 y posteriores usa /source-charset y /execution-charset para especificar los juegos de caracteres de fuente y de ejecución respectivamente.

(hasta C++23)

Para una secuencia de dos o más tókenes literales de cadena adyacentes, se determina un prefijo de codificación común como se específica aquí. Cada literal cadena de este tipo se considera que tiene ese prefijo común (la conversión de caracteres se mueve a la fase 3).

(desde C++23)

Fase 6

Los literales de cadena contiguos se concatenan.

Fase 7

Tiene lugar la compilación: cada token de preprocesamiento se convierte en un token. Los tókenes son analizados sintácticamente y semánticamente y traducidos como una unidad de traducción.

Fase 8

Se examina cada unidad de traducción para producir una lista de instancias de plantillas requeridas, incluidos las solicitadas por instancias explícitas. Se localizan las definiciones de las plantillas, se realizan las instanciaciones requeridas para producir unidades de instanciación.

Fase 9

Las unidades de traducción, las unidades de instanciación y los componentes de biblioteca necesarios para satisfacer las referencias externas se recopilan en una imagen de programa que contiene la información necesaria para la ejecución en su entorno de ejecución.

Notas

Algunos compiladores no implementan las unidades de instanciación (también conocidas como repositorio de plantillas o registros de plantillas) y simplemente compila cada instanciación de plantilla en la fase 7, almacenando el código en el archivo objeto donde se solicita implícita o explícitamente, y luego el enlazador une esas instancias compiladas en una en la fase 9.

Referencias

  • El estándar C++20 (ISO/IEC 14882:2020):
  • 5.2 Phases of translation [lex.phases]
  • El estándar C++17 (ISO/IEC 14882:2017):
  • 5.2 Phases of translation [lex.phases]
  • El estándar C++14 (ISO/IEC 14882:2014):
  • 2.2 Phases of translation [lex.phases]
  • El estándar C++11 (ISO/IEC 14882:2011):
  • 2.2 Phases of translation [lex.phases]
  • El estándar C++03 (ISO/IEC 14882:2003):
  • 2.1 Phases of translation [lex.phases]
  • El estándar C++98 (ISO/IEC 14882:1998):
  • 2.1 Phases of translation [lex.phases]

Véase también

Documentación de C para Fases de traducción