[flang] Quash multiple blanks when preprocessing.

Original-commit: flang-compiler/f18@d91680b469
Reviewed-on: https://github.com/flang-compiler/f18/pull/87
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler 2018-05-11 11:15:20 -07:00
parent e13ee629f8
commit f1840f1601
4 changed files with 54 additions and 10 deletions

View File

@ -344,6 +344,9 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement(
}
j = k; // advance to the terminal ')'
}
if (result.HasRedundantBlanks()) {
result.RemoveRedundantBlanks();
}
return {result};
}

View File

@ -89,7 +89,7 @@ void Prescanner::Prescan(ProvenanceRange range) {
}
dir += '\n';
TokenSequence tokens{dir, allSources.AddCompilerInsertion(dir).start()};
tokens.Emit(&cooked_);
tokens.Emit(cooked_);
}
}
@ -160,16 +160,16 @@ void Prescanner::Statement() {
case LineClassification::Kind::PreprocessorDirective:
Say("preprocessed line resembles a preprocessor directive"_en_US,
preprocessed->GetProvenanceRange());
preprocessed->ToLowerCase().Emit(&cooked_);
preprocessed->ToLowerCase().Emit(cooked_);
break;
case LineClassification::Kind::CompilerDirective:
NormalizeCompilerDirectiveCommentMarker(*preprocessed);
preprocessed->ToLowerCase();
SourceFormChange(preprocessed->ToString());
preprocessed->Emit(&cooked_);
preprocessed->Emit(cooked_);
break;
case LineClassification::Kind::Source:
preprocessed->ToLowerCase().Emit(&cooked_);
preprocessed->ToLowerCase().Emit(cooked_);
break;
}
} else {
@ -177,7 +177,7 @@ void Prescanner::Statement() {
if (line.kind == LineClassification::Kind::CompilerDirective) {
SourceFormChange(tokens.ToString());
}
tokens.Emit(&cooked_);
tokens.Emit(cooked_);
cooked_.Put('\n', newlineProvenance);
}
directiveSentinel_ = nullptr;

View File

@ -144,9 +144,47 @@ TokenSequence &TokenSequence::ToLowerCase() {
return *this;
}
void TokenSequence::Emit(CookedSource *cooked) const {
cooked->Put(&char_[0], char_.size());
cooked->PutProvenanceMappings(provenances_);
bool TokenSequence::HasRedundantBlanks() const {
std::size_t tokens{SizeInTokens()};
bool lastWasBlank{false};
for (std::size_t j{0}; j < tokens; ++j) {
bool isBlank{TokenAt(j).IsBlank()};
if (isBlank && lastWasBlank) {
return true;
}
lastWasBlank = isBlank;
}
return false;
}
TokenSequence &TokenSequence::RemoveRedundantBlanks() {
std::size_t tokens{SizeInTokens()};
TokenSequence result;
bool lastWasBlank{false};
for (std::size_t j{0}; j < tokens; ++j) {
bool isBlank{TokenAt(j).IsBlank()};
if (isBlank && lastWasBlank) {
continue;
}
lastWasBlank = isBlank;
result.Put(*this, j);
}
*this = std::move(result);
return *this;
}
void TokenSequence::Emit(CookedSource &cooked) const {
cooked.Put(&char_[0], char_.size());
cooked.PutProvenanceMappings(provenances_);
}
void TokenSequence::Dump(std::ostream &o) const {
o << "TokenSequence has " << char_.size() << " chars; nextStart_ "
<< nextStart_ << '\n';
for (std::size_t j{0}; j < start_.size(); ++j) {
o << '[' << j << "] @ " << start_[j] << " '" << TokenAt(j).ToString()
<< "'\n";
}
}
Provenance TokenSequence::GetTokenProvenance(
@ -176,5 +214,4 @@ ProvenanceRange TokenSequence::GetIntervalProvenanceRange(
ProvenanceRange TokenSequence::GetProvenanceRange() const {
return GetIntervalProvenanceRange(0, start_.size());
}
} // namespace Fortran::parser

View File

@ -23,6 +23,7 @@
#include "provenance.h"
#include <cstddef>
#include <cstring>
#include <ostream>
#include <string>
#include <utility>
#include <vector>
@ -106,7 +107,10 @@ public:
char *GetMutableCharData() { return &char_[0]; }
TokenSequence &ToLowerCase();
void Emit(CookedSource *) const;
bool HasRedundantBlanks() const;
TokenSequence &RemoveRedundantBlanks();
void Emit(CookedSource &) const;
void Dump(std::ostream &) const;
private:
std::size_t TokenBytes(std::size_t token) const {