📄 asformatter.cpp
字号:
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* ASFormatter.cpp
*
* This file is a part of "Artistic Style" - an indentation and
* reformatting tool for C, C++, C# and Java source files.
* http://astyle.sourceforge.net
*
* The "Artistic Style" project, including all files needed to
* compile it, is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this project; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
#include "astyle.h"
#include <algorithm>
#include <fstream>
#include <iostream>
#ifdef __VMS
#include <assert>
#else
#include <cassert>
#endif
// can trace only if NDEBUG is not defined
#ifndef NDEBUG
// #define TRACEunpad
// #define TRACEcomment
// #define TRACEheader
// #define TRACEbracket
// #define TRACEarray
#if defined(TRACEunpad) || defined(TRACEcomment) || defined(TRACEheader) \
|| defined(TRACEbracket) || defined(TRACEarray)
ofstream *traceOutF;
#define TRACEF
#endif
#endif
#ifdef TRACEunpad
#define TRunpad(a,b,c) if(b > 0 || c > 0) *traceOutF << outLineNumber << " " << b << a << c << endl
#else
#define TRunpad(a,b,c) ((void)0)
#endif
#ifdef TRACEcomment
#define TRcomment(a) *traceOutF << outLineNumber << " " << a << endl
#else
#define TRcomment(a) ((void)0)
#endif
#ifdef TRACEheader
#define TRxtra(a) *traceOutF << outLineNumber << " " << a << endl
#else
#define TRxtra(a) ((void)0)
#endif
#ifdef TRACEbracket
#define TRbracket(a) *traceOutF << outLineNumber << " " << a << endl
#else
#define TRbracket(a) ((void)0)
#endif
#ifdef TRACEarray
#define TRarray(a) *traceOutF << outLineNumber << " " << a << endl
#else
#define TRarray(a) ((void)0)
#endif
#define INIT_CONTAINER(container, value) {if ( (container) != NULL ) delete (container); (container) = (value); }
#define DELETE_CONTAINER(container) {if ( (container) != NULL ) delete (container); }
#define IS_A(a,b) ( ((a) & (b)) == (b))
using namespace std;
namespace astyle
{
vector<const string*> ASFormatter::headers;
vector<const string*> ASFormatter::nonParenHeaders;
vector<const string*> ASFormatter::preDefinitionHeaders;
vector<const string*> ASFormatter::preCommandHeaders;
vector<const string*> ASFormatter::operators;
vector<const string*> ASFormatter::assignmentOperators;
vector<const string*> ASFormatter::castOperators;
/**
* Constructor of ASFormatter
*/
ASFormatter::ASFormatter()
{
preBracketHeaderStack = NULL;
bracketTypeStack = NULL;
parenStack = NULL;
lineCommentNoIndent = false;
sourceIterator = NULL;
bracketFormatMode = NONE_MODE;
shouldPadOperators = false;
shouldPadParensOutside = false;
shouldPadParensInside = false;
shouldUnPadParens = false;
shouldBreakOneLineBlocks = true;
shouldBreakOneLineStatements = true;
shouldConvertTabs = false;
shouldBreakBlocks = false;
shouldBreakClosingHeaderBlocks = false;
shouldBreakClosingHeaderBrackets = false;
shouldBreakElseIfs = false;
#ifdef TRACEF
// create a trace text file
string filename = "tracef.txt";
char* env = getenv("HOME");
if (env != NULL)
filename = string(env) + string("/tracef.txt");
else
{
env = getenv("USERPROFILE");
if (env != NULL)
filename = string(env) + string("\\My Documents\\tracef.txt");
else
{
cout << "\nCould not open tracef.txt\n" << endl;
exit(1);
}
}
traceOutF = new ofstream(filename.c_str());
#endif
}
/**
* Destructor of ASFormatter
*/
ASFormatter::~ASFormatter()
{
DELETE_CONTAINER(preBracketHeaderStack);
#ifdef TRACEF
delete traceOutF;
#endif
}
/**
* initialization of static data of ASFormatter.
*/
void ASFormatter::staticInit()
{
static int formatterFileType = 9; // initialized with an invalid type
if (fileType == formatterFileType) // don't build unless necessary
return;
formatterFileType = fileType;
headers.clear();
nonParenHeaders.clear();
assignmentOperators.clear();
operators.clear();
preDefinitionHeaders.clear();
preCommandHeaders.clear();
castOperators.clear();
ASResource::buildHeaders(headers, fileType);
ASResource::buildNonParenHeaders(nonParenHeaders, fileType);
ASResource::buildAssignmentOperators(assignmentOperators);
ASResource::buildOperators(operators);
ASResource::buildPreDefinitionHeaders(preDefinitionHeaders);
ASResource::buildPreCommandHeaders(preCommandHeaders);
ASResource::buildCastOperators(castOperators);
}
/**
* initialize the ASFormatter.
*
* init() should be called every time a ASFormatter object is to start
* formatting a NEW source file.
* init() recieves a pointer to a DYNAMICALLY CREATED ASSourceIterator object
* that will be used to iterate through the source code. This object will be
* deleted during the ASFormatter's destruction, and thus should not be
* deleted elsewhere.
*
* @param iter a pointer to the DYNAMICALLY CREATED ASSourceIterator object.
*/
void ASFormatter::init(ASSourceIterator *si)
{
staticInit();
ASBeautifier::init(si);
ASEnhancer::init(ASBeautifier::getIndentLength(),
ASBeautifier::getIndentString(),
ASBeautifier::getCStyle(),
ASBeautifier::getJavaStyle(),
ASBeautifier::getSharpStyle(),
ASBeautifier::getCaseIndent(),
ASBeautifier::getEmptyLineFill());
sourceIterator = si;
INIT_CONTAINER(preBracketHeaderStack, new vector<const string*>);
INIT_CONTAINER(bracketTypeStack, new vector<BracketType>);
bracketTypeStack->push_back(NULL_TYPE);
INIT_CONTAINER(parenStack, new vector<int>);
parenStack->push_back(0);
currentHeader = NULL;
currentLine = string("");
readyFormattedLine = string("");
formattedLine = "";
currentChar = ' ';
previousChar = ' ';
previousCommandChar = ' ';
previousNonWSChar = ' ';
quoteChar = '"';
charNum = 0;
spacePadNum = 0;
previousReadyFormattedLineLength = string::npos;
templateDepth = 0;
previousBracketType = NULL_TYPE;
previousOperator = NULL;
isVirgin = true;
isInLineComment = false;
isInComment = false;
isInPreprocessor = false;
doesLineStartComment = false;
isInQuote = false;
isSpecialChar = false;
isNonParenHeader = true;
foundNamespaceHeader = false;
foundClassHeader = false;
foundPreDefinitionHeader = false;
foundPreCommandHeader = false;
foundCastOperator = false;
foundQuestionMark = false;
isInLineBreak = false;
endOfCodeReached = false;
isLineReady = false;
isPreviousBracketBlockRelated = true;
isInPotentialCalculation = false;
shouldReparseCurrentChar = false;
passedSemicolon = false;
passedColon = false;
isInTemplate = false;
isInBlParen = false;
shouldBreakLineAfterComments = false;
isImmediatelyPostComment = false;
isImmediatelyPostLineComment = false;
isImmediatelyPostEmptyBlock = false;
isImmediatelyPostPreprocessor = false;
isPrependPostBlockEmptyLineRequested = false;
isAppendPostBlockEmptyLineRequested = false;
prependEmptyLine = false;
appendOpeningBracket = false;
foundClosingHeader = false;
previousReadyFormattedLineLength = 0;
isImmediatelyPostHeader = false;
isInHeader = false;
#ifdef TRACEF
// fileName will be empty if ASTYLE_LIB is defined
if (fileName.empty())
*traceOutF << "new file" << endl;
else
*traceOutF << fileName << endl;
#endif
}
/**
* get the next formatted line.
*
* @return formatted line.
*/
string ASFormatter::nextLine()
{
// these are reset with each new line
const string *newHeader;
bool isInVirginLine = isVirgin;
isCharImmediatelyPostComment = false;
isPreviousCharPostComment = false;
isCharImmediatelyPostLineComment = false;
isCharImmediatelyPostOpenBlock = false;
isCharImmediatelyPostCloseBlock = false;
isCharImmediatelyPostTemplate = false;
while (!isLineReady)
{
if (shouldReparseCurrentChar)
shouldReparseCurrentChar = false;
else if (!getNextChar())
{
breakLine();
return beautify(readyFormattedLine);
}
else // stuff to do when reading a new character...
{
// make sure that a virgin '{' at the begining ofthe file will be treated as a block...
if (isInVirginLine && currentChar == '{')
previousCommandChar = '{';
isPreviousCharPostComment = isCharImmediatelyPostComment;
isCharImmediatelyPostComment = false;
isCharImmediatelyPostTemplate = false;
}
//if (inLineNumber >= 185)
// int x = 1;
if (isInLineComment)
{
appendCurrentChar();
// explicitely break a line when a line comment's end is found.
if (charNum + 1 == (int) currentLine.length())
{
isInLineBreak = true;
isInLineComment = false;
isImmediatelyPostLineComment = true;
currentChar = 0; //make sure it is a neutral char.
}
continue;
}
else if (isInComment)
{
if (isSequenceReached("*/"))
{
isInComment = false;
isImmediatelyPostComment = true;
appendSequence(AS_CLOSE_COMMENT);
goForward(1);
}
else
appendCurrentChar();
continue;
}
// not in line comment or comment
else if (isInQuote)
{
if (isSpecialChar)
{
isSpecialChar = false;
appendCurrentChar();
}
else if (currentChar == '\\')
{
isSpecialChar = true;
appendCurrentChar();
}
else if (quoteChar == currentChar)
{
isInQuote = false;
appendCurrentChar();
}
else
{
appendCurrentChar();
}
continue;
}
// handle white space - needed to simplify the rest.
if (isWhiteSpace(currentChar) || isInPreprocessor)
{
appendCurrentChar();
continue;
}
/* not in MIDDLE of quote or comment or white-space of any type ... */
if (isSequenceReached("//"))
{
if (currentLine[charNum+2] == '\xf2') // check for windows line marker
isAppendPostBlockEmptyLineRequested = false;
isInLineComment = true;
// do not indent if in column 1 or 2
if (lineCommentNoIndent == false)
{
if (charNum == 0)
lineCommentNoIndent = true;
else if (charNum == 1 && currentLine[0] == ' ')
lineCommentNoIndent = true;
}
// move comment if spaces were added or deleted
if (lineCommentNoIndent == false && spacePadNum != 0)
adjustComments();
formattedLineCommentNum = formattedLine.length();
appendSequence(AS_OPEN_LINE_COMMENT);
goForward(1);
// explicitely break a line when a line comment's end is found.
if (charNum + 1 == (int) currentLine.length())
{
isInLineBreak = true;
isInLineComment = false;
isImmediatelyPostLineComment = true;
currentChar = 0; //make sure it is a neutral char.
}
continue;
}
else if (isSequenceReached("/*"))
{
isInComment = true;
if (spacePadNum != 0)
adjustComments();
formattedLineCommentNum = formattedLine.length();
appendSequence(AS_OPEN_COMMENT);
goForward(1);
continue;
}
else if (currentChar == '"' || currentChar == '\'')
{
isInQuote = true;
quoteChar = currentChar;
appendCurrentChar();
continue;
}
/* not in quote or comment or white-space of any type ... */
// check if in preprocessor
// ** isInPreprocessor will be automatically reset at the begining
// of a new line in getnextChar()
if (currentChar == '#')
{
isInPreprocessor = true;
appendCurrentChar();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -