mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 07:27:45 +00:00
LibCpp: Correctly parse lines that end in '\'
Such lines should be considered to be joined into the next line. This makes multiline preprocessor stuff "work".
This commit is contained in:
parent
8fefbfd5ac
commit
dc68c765b7
3 changed files with 62 additions and 7 deletions
|
@ -556,8 +556,16 @@ Vector<Token> Lexer::lex()
|
||||||
begin_token();
|
begin_token();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
while (peek() && peek() != '\n')
|
while (peek()) {
|
||||||
consume();
|
if (peek() == '\\' && peek(1) == '\n') {
|
||||||
|
consume();
|
||||||
|
consume();
|
||||||
|
} else if (peek() == '\n') {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
consume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
commit_token(Token::Type::PreprocessorStatement);
|
commit_token(Token::Type::PreprocessorStatement);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,25 @@ Preprocessor::Preprocessor(const String& filename, const StringView& program)
|
||||||
: m_filename(filename)
|
: m_filename(filename)
|
||||||
, m_program(program)
|
, m_program(program)
|
||||||
{
|
{
|
||||||
m_lines = m_program.split_view('\n', true);
|
GenericLexer program_lexer { m_program };
|
||||||
|
for (;;) {
|
||||||
|
if (program_lexer.is_eof())
|
||||||
|
break;
|
||||||
|
auto line = program_lexer.consume_until('\n');
|
||||||
|
bool has_multiline = false;
|
||||||
|
while (line.ends_with('\\') && !program_lexer.is_eof()) {
|
||||||
|
auto continuation = program_lexer.consume_until('\n');
|
||||||
|
line = StringView { line.characters_without_null_termination(), line.length() + continuation.length() + 1 };
|
||||||
|
// Append an empty line to keep the line count correct.
|
||||||
|
m_lines.append({});
|
||||||
|
has_multiline = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_multiline)
|
||||||
|
m_lines.last() = line;
|
||||||
|
else
|
||||||
|
m_lines.append(line);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const String& Preprocessor::process()
|
const String& Preprocessor::process()
|
||||||
|
@ -45,9 +63,28 @@ const String& Preprocessor::process()
|
||||||
|
|
||||||
static void consume_whitespace(GenericLexer& lexer)
|
static void consume_whitespace(GenericLexer& lexer)
|
||||||
{
|
{
|
||||||
lexer.ignore_while([](char ch) { return isspace(ch); });
|
auto ignore_line = [&] {
|
||||||
if (lexer.peek() == '/' && lexer.peek(1) == '/')
|
for (;;) {
|
||||||
lexer.ignore_until([](char ch) { return ch == '\n'; });
|
if (lexer.consume_specific("\\\n"sv)) {
|
||||||
|
lexer.ignore(2);
|
||||||
|
} else {
|
||||||
|
lexer.ignore_until('\n');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for (;;) {
|
||||||
|
if (lexer.consume_specific("//"sv))
|
||||||
|
ignore_line();
|
||||||
|
else if (lexer.consume_specific("/*"sv))
|
||||||
|
lexer.ignore_until("*/");
|
||||||
|
else if (lexer.next_is("\\\n"sv))
|
||||||
|
lexer.ignore(2);
|
||||||
|
else if (lexer.is_eof() || !lexer.next_is(isspace))
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
lexer.ignore();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Preprocessor::PreprocessorKeyword Preprocessor::handle_preprocessor_line(const StringView& line)
|
Preprocessor::PreprocessorKeyword Preprocessor::handle_preprocessor_line(const StringView& line)
|
||||||
|
|
|
@ -13,7 +13,9 @@ int main(int argc, char** argv)
|
||||||
Core::ArgsParser args_parser;
|
Core::ArgsParser args_parser;
|
||||||
const char* path = nullptr;
|
const char* path = nullptr;
|
||||||
bool tokens_mode = false;
|
bool tokens_mode = false;
|
||||||
|
bool preprocess_mode = false;
|
||||||
args_parser.add_option(tokens_mode, "Print Tokens", "tokens", 'T');
|
args_parser.add_option(tokens_mode, "Print Tokens", "tokens", 'T');
|
||||||
|
args_parser.add_option(preprocess_mode, "Print Preprocessed source", "preprocessed", 'P');
|
||||||
args_parser.add_positional_argument(path, "Cpp File", "cpp-file", Core::ArgsParser::Required::No);
|
args_parser.add_positional_argument(path, "Cpp File", "cpp-file", Core::ArgsParser::Required::No);
|
||||||
args_parser.parse(argc, argv);
|
args_parser.parse(argc, argv);
|
||||||
|
|
||||||
|
@ -26,7 +28,15 @@ int main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
auto content = file->read_all();
|
auto content = file->read_all();
|
||||||
StringView content_view(content);
|
StringView content_view(content);
|
||||||
::Cpp::Parser parser(content_view, path);
|
|
||||||
|
::Cpp::Preprocessor processor(path, content_view);
|
||||||
|
auto preprocessed_content = processor.process();
|
||||||
|
if (preprocess_mode) {
|
||||||
|
outln(preprocessed_content);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
::Cpp::Parser parser(preprocessed_content, path);
|
||||||
if (tokens_mode) {
|
if (tokens_mode) {
|
||||||
parser.print_tokens();
|
parser.print_tokens();
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue