#P8289. [省选联考 2022] 预处理器
[省选联考 2022] 预处理器
Problem Description
Macros are a feature of the C/C++ language. They perform text replacement based on predefined rules (also called “macro expansion”), and can be used to define constants, reduce repeated typing, and so on. For example:
#define PI 3.14159
double area = PI * r * r;
After macro expansion, the above code becomes:
double area = 3.14159 * r * r;
Here, the macro definition line becomes an empty line, and macros in other lines are expanded into the text specified by their rules.
In C/C++, macro processing during compilation is done by the preprocessor. Your task is to implement a simplified preprocessor with the following requirements:
-
The code consists of lines. Each line, except for the newline character at the end, consists only of printable ASCII characters (ASCII codes in the range ). Each line is either a preprocessing directive (starting with
#) or plain text (otherwise). -
The preprocessor processes the code line by line:
- If it is a preprocessing directive, execute the directive and output an empty line.
- If it is plain text, perform macro expansion on it and output the result.
-
There are two kinds of preprocessing directives: the macro definition directive
#defineand the macro undefinition directive#undef.- The macro definition directive has the format
#define <name> <content>. The first part#defineis the directive name, the second part<name>is the macro name to define, and the third part<content>is the expansion text to define. - The macro undefinition directive has the format
#undef <name>. The first part#undefis the directive name, and the second part<name>is the macro name to undefine.
In both directives above, adjacent parts are separated by exactly one space.
<name>is an identifier (one or more characters) consisting of uppercase/lowercase letters, digits, and underscores.<content>may contain any printable ASCII characters (zero or more characters). The effective scope of a macro definition starts from the line where it is defined and ends at the nearest subsequent undefinition line whose macro name matches it (if there is no corresponding undefinition, the scope extends to the end of the file). - The macro definition directive has the format
When expanding macros in plain text, treat each maximal consecutive segment of uppercase/lowercase letters, digits, and underscores in a line as an identifier (not a part of it), and treat the rest as other characters. From left to right, expand identifiers in the text in order:
-
If an identifier is a currently effective macro name, replace it with its corresponding expansion content. At this time, this macro name enters the “being expanded” state until this whole process ends. Otherwise, keep the identifier unchanged. For example, if macro
Ais defined asb, then textAexpands tob(replacement happens), textBstill expands toB(undefined, no replacement), textAAstill expands toAA(AAis a different identifier fromA, undefined), and textA*Bexpands tob*B. -
After a replacement happens, if the expansion content contains identifiers, repeat the expansion operation above. This is called “multiple expansion”. For example, if macro
Ais defined asB, and macroBis defined asc, then the expansion result of textAisc. -
If the macro name to be expanded is the same as some macro name that is currently “being expanded”, this is called “recursive expansion”, and this macro name is no longer expanded. This rule is used to prevent infinite recursive expansion. For example, if macro
Ais defined asB+a, and macroBis defined asA+b, then the expansion result of textAisA+b+a. Since the initialAis in the “being expanded” state, theAinA+b+ais no longer expanded. -
Other characters are kept unchanged.
Note: For simplification, the requirements of this problem are not exactly the same as the description in the C/C++ language standard. Please follow the requirements above. The most obvious difference is that this problem has only two kinds of tokens: identifiers and other characters. There are no numbers, strings, comments, etc.
Input Format
The first line contains a positive integer , indicating the number of code lines to process.
The next lines are the code to be processed.
Output Format
Output lines, which are the results after preprocessing each input line.
5
#define BEGIN {
#define END }
#define INTEGER int
class C BEGIN INTEGER x; END;
INTEGER main() BEGIN C c; END
class C { int x; };
int main() { C c; }
见附件中的 preprocessor/preprocessor2.in
见附件中的 preprocessor/preprocessor2.ans
见附件中的 preprocessor/preprocessor3.in
见附件中的 preprocessor/preprocessor3.ans
Hint
[Constraints]
For of the testdata, there will be no macro definition directives #define and no macro undefinition directives #undef.
For another of the testdata, there will be no multiple expansion, and there will be no macro undefinition directives #undef.
For another of the testdata, there will be no multiple expansion.
For another of the testdata, there will be no recursive expansion.
For the remaining testdata, there are no special restrictions.
For of the testdata, . The number of characters in each input line does not exceed , and it is guaranteed that the number of characters in each output line does not exceed (character counts do not include the trailing newline). It is guaranteed that the preprocessing directives in the input are all valid, including but not limited to:
- The
#character appears only as the first character of lines that are preprocessing directives, and does not appear anywhere else (including in preprocessing directives and plain text). - The formats of macro definition and undefinition directives are correct and strictly follow the format described in the statement.
- The same macro will not be defined again before it is undefined.
- A macro to be undefined has been defined before and has not yet been undefined.
That is, you do not need to do any syntax or semantic error checking.
[Hint]
When reading input for this problem, it is recommended to use the line-based string input function in C++, for example:
#include <iostream>
#include <string>
using namespace std;
string line;
// Read one line from cin and store it in line (the newline is discarded)
getline(cin, line);
You may also use the fgets function provided by C, for example:
#include <stdio.h>
#define MAX_LEN 200
char line[MAX_LEN];
// Read one line from stdin and store it in line (including the newline)
fgets(line, MAX_LEN, stdin);
Note: After reading the line count , you may need to read one extra line to ignore the following newline character.
Translated by ChatGPT 5