⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 asformatter.cpp

📁 著名的代码自动缩进软件ASTYLE的源码,为1.21版本,支持C/C++/JAVA的各种格式的排版,支持自定的样式,功能强大
💻 CPP
📖 第 1 页 / 共 5 页
字号:
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *
 *   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 + -