📄 ceditdoc_funclist1.cpp
字号:
// $Id: CEditDoc_FuncList1.cpp,v 1.2 2005/01/30 10:25:34 Administrator Exp $
/*! @file
@brief アウトライン解析
@author genta
@date 2004.08.08 作成
$Revision: 1.2 $
*/
/*
Copyright (C) 1998-2001, Norio Nakatani
Copyright (C) 2002, frozen
This source code is designed for sakura editor.
Please contact the copyright holders to use this code for other purpose.
*/
#include <string.h>
#include "global.h"
#include "CEditDoc.h"
#include "CFuncInfoArr.h"
#include "CDocLine.h"
#include "charcode.h"
// Mar. 15, 2000 genta
// From Here
/*!
スペースの判定
*/
inline bool C_IsSpace( char c ){
return ('\t' == c ||
' ' == c ||
CR == c ||
LF == c
);
}
/*!
関数に用いることができる文字かどうかの判定
*/
inline bool C_IsWordChar( char c ){
return ( '_' == c ||
':' == c ||
'~' == c ||
('a' <= c && c <= 'z' )||
('A' <= c && c <= 'Z' )||
('0' <= c && c <= '9' )
);
}
// To Here
// From Here Apr. 1, 2001 genta
/*!
特殊な関数名 "operator" かどうかを判定する。
文字列が"operator"それ自身か、あるいは::の後ろにoperatorと続いて
終わっているときにoperatorと判定。
演算子の評価順序を保証するため2つのif文に分けてある
@param szStr 判定対象の文字列
@param nLen 文字列の長さ。
本質的には不要であるが、高速化のために既にある値を利用する。
*/
static bool C_IsOperator( char* szStr, int nLen )
{
if( nLen >= 8 && szStr[ nLen - 1 ] == 'r' ){
if( nLen > 8 ?
strcmp( szStr + nLen - 9, ":operator" ) == 0 : // メンバー関数による定義
strcmp( szStr, "operator" ) == 0 // friend関数による定義
){
return true;
}
}
return false;
}
// To Here Apr. 1, 2001 genta
/*!
改行直前を \ でエスケープしているかどうか判定
*/
static bool C_IsLineEsc(const char *s, int len)
{
if( len > 3 && s[len - 3] == '\\' && s[len - 2] == '\r' && s[len - 1] == '\n' ) {return(true);}
if( len > 3 && s[len - 3] == '\\' && s[len - 2] == '\n' && s[len - 1] == '\r' ) {return(true);}
if( len > 2 && s[len - 2] == '\\' && s[len - 1] == '\n' ) {return(true);}
if( len > 2 && s[len - 2] == '\\' && s[len - 1] == '\r' ) {return(true);}
return(false);
}
/*!
Cプリプロセッサの #if/ifdef/ifndef - #else - #endif状態管理クラス
ネストレベルは32レベル=(sizeof(int) * 8)まで
*/
class CCppPreprocessMng {
public:
CCppPreprocessMng(void) :
m_stackptr( 0 ), m_bitpattern( 1 ), m_enablebuf( 0 ), m_maxnestlevel( 32 ), m_ismultiline( false )
{}
int ScanLine(const char*, int);
private:
bool m_ismultiline; //!< 複数行のディレクティブ
int m_maxnestlevel; //!< ネストレベルの最大値
int m_stackptr; //!< ネストレベル
/*!
ネストレベルに対応するビットパターン
m_stackptr = n の時,下から(n-1)bit目に1が入っている
*/
unsigned int m_bitpattern;
unsigned int m_enablebuf; //!< 処理の有無を保存するバッファ
};
/*!
Cプリプロセッサの #if/ifdef/ifndef - #else - #endifを元に
処理の必要性を判定する.
与えられた1行の文字列を先頭から走査し,C/C++での走査が必要な場合は
先頭の空白を除いた開始位置を,不要な場合はlengthを返す.
呼び出し側では戻り値から解析を始めるので,
lengthを返すことはすべて空白と見なすことになる.
ネストの最大を超えた場合には記憶域がないために判定は不可能となるが,
ネストレベルだけは管理する.
@param str [in] 1行の文字列
@param length [in] 文字列長
@return C解析開始位置.処理不要の場合はlength(行末までスキップ).
@par elifの扱い
if (A) elif (B) elif (C) else (D) endifのような場合には(A)-(D)のどれか1つ
だけが実行される.しかし,そうなると1ビットでは管理できないしネストを
囲むようなケースでelifを使うことはあまり無いと勝手に決めて見なかったことにする.
@author genta
@date 2004.08.10 新規作成
@date 2004.08.13 zenryaku 複数行のディレクティブに対応
*/
int CCppPreprocessMng::ScanLine( const char* str, int length )
{
const char* lastptr = str + length; // 処理文字列末尾
const char* p; // 処理中の位置
// skip whitespace
for( p = str; C_IsSpace( *p ) && p < lastptr ; ++p )
;
if( lastptr <= p )
return length; // 空行のため処理不要
if(m_ismultiline){ // 複数行のディレクティブは無視
m_ismultiline = C_IsLineEsc(str, length); // 行末が \ で終わっていないか
return length;
}
if( *p != '#' ){ // プリプロセッサ以外の処理はメイン部に任せる
if( m_enablebuf ){
return length; // 1ビットでも1となっていたら無視
}
return p - str;
}
++p; // #をスキップ
// skip whitespace
for( ; C_IsSpace( *p ) && p < lastptr ; ++p )
;
// ここからPreprocessor directive解析
if( p + 2 + 2 < lastptr && strncmp( p, "if", 2 ) == 0 ){ // sizeof( "if" ) == 2
// if
p += 2;
int enable = 0; // 0: 処理しない, 1: else以降が有効, 2: 最初が有効,
// if 0は最初が無効部分とみなす.
// それ以外のif/ifdef/ifndefは最初が有効部分と見なす
// 最初の条件によってこの時点ではp < lastptrなので判定省略
if( C_IsSpace( *p ) ){
// if 0 チェック
// skip whitespace
for( ; C_IsSpace( *p ) && p < lastptr ; ++p )
;
if( *p == '0' ){
enable = 1;
}
else {
enable = 2;
}
}
else if(
( p + 3 < lastptr && strncmp( p, "def", 3 ) == 0 ) ||
( p + 4 < lastptr && strncmp( p, "ndef", 4 ) == 0 )){
enable = 2;
}
// 保存領域の確保とビットパターンの設定
if( enable > 0 ){
m_bitpattern = 1 << m_stackptr;
++m_stackptr;
if( enable == 1 ){
m_enablebuf |= m_bitpattern;
}
}
}
else if( p + 4 < lastptr && strncmp( p, "else", 4 ) == 0 ){ // sizeof( "else" ) == 4
if( m_stackptr < m_maxnestlevel ){
m_enablebuf ^= m_bitpattern;
}
}
else if( p + 5 < lastptr && strncmp( p, "endif", 5 ) == 0 ){ // sizeof( "endif" ) == 5
if( m_stackptr > 0 ){
--m_stackptr;
m_enablebuf &= ~m_bitpattern;
m_bitpattern = ( 1 << ( m_stackptr - 1 ));
}
}
else{
m_ismultiline = C_IsLineEsc(str, length); // 行末が \ で終わっていないか
}
return length; // 基本的にプリプロセッサ指令は無視
}
/*!
@brief C/C++関数リスト作成
@param bVisibleMemberFunc クラス、構造体定義内のメンバ関数の宣言をアウトライン解析結果に登録する場合はtrue
@par MODE一覧
- 0 通常
- 20 Single quotation文字列読み込み中
- 21 Double quotation文字列読み込み中
- 8 コメント読み込み中
- 1 単語読み込み中
- 2 記号列読み込み中
- 999 長過ぎる単語無視中
@par FuncIdの値の意味
10の位で目的別に使い分けている.C/C++用は10位が0
- 1: 宣言
- 2: 通常の関数 (追加文字列無し)
- 3: クラス("クラス")
- 4: 構造体 ("構造体")
- 5: 列挙体("列挙体")
- 6: 共用体("共用体")
- 7: 名前空間("名前空間")
@param pcFuncInfoArr [out] 関数一覧を返すためのクラス。
ここに関数のリストを登録する。
*/
void CEditDoc::MakeFuncList_C( CFuncInfoArr* pcFuncInfoArr ,bool bVisibleMemberFunc )
{
const char* pLine;
int nLineLen;
int nLineCount;
int i;
// 2002/10/27 frozen ここから
// nNestLevelを nNestLevel_global を nNestLevel_func に分割した。
int nNestLevel_global = 0; // nNestLevel_global 関数外の {}のレベル
int nNestLevel_func = 0; // nNestLevel_func 関数の定義、および関数内の {}のレベル
// int nNestLevel2; // nNestLevel2 ()に対する位置 // 2002/10/27 frozen nNastLevel_fparamとnMode2のM2_FUNC_NAME_ENDで代用
int nNestLevel_fparam = 0; // ()のレベル
int nNestPoint_class = 0; // 外側から何番目の{がクラスの定義を囲む{か? (一番外側なら1、0なら無し。bVisibleMemberFuncがfalseの時のみ有効。trueでは常に0)
// 2002/10/27 frozen ここまで
int nCharChars; // 多バイト文字を読み飛ばすためのもの
char szWordPrev[256]; // 1つ前のword
char szWord[256]; // 現在解読中のwordを入れるところ
int nWordIdx = 0;
int nMaxWordLeng = 100; // 許容されるwordの最大長さ
int nMode; // 現在のstate
// 2002/10/27 frozen ここから
//! 状態2
enum MODE2
{
M2_NORMAL = 0x00, //!< 通常
M2_NAMESPACE_SAVE = 0x11, //!< ネームスペース名調査中
// 「通常」状態で単語 "class" "struct" "union" "enum" "namespace"を読み込むと、この状態になり、';' '{' ',' '>' '='を読み込むと「通常」になる。
//
// ':' を読み込むと「ネームスペース名調査完了」へ移行すると同時に
// szWordをszTokenNameに保存し、あとで ':' 又は '{' の直前の単語が調べられるようにしている。
// これは "__declspec( dllexport )"のように"class"とクラス名の間にキーワードが書いてある場合でもクラス名を取得できるようにするため。
//
// '<' を読み込むと「テンプレートクラス名調査中」に移行する。
M2_TEMPLATE_SAVE = 0x12, //!< テンプレートクラス名調査中
// ';' '{'を読み込むと「通常」になる。
// また、この状態の間は単語を区切る方法を一時的に変更し、
// 「template_name <paramA,paramB>」のような文字列を一つの単語をみなすようにする。
// これは特殊化したクラステンプレートを実装する際の構文で有効に働く。
M2_NAMESPACE_END = 0x13, //!< ネームスペース名調査完了。(';' '{' を読み込んだ時点で「通常」になる。 )
M2_FUNC_NAME_END = 0x14, //!< 関数名調査完了。(';' '{' を読み込んだ時点で「通常」になる。 )
M2_AFTER_EQUAL = 0x05, //!< '='の後。
//「通常」かつ nNestLevel_fparam==0 で'='が見つかるとこの状態になる。(ただし "opreator"の直後は除く)
// ';'が見つかると「通常」に戻る。
// int val=abs(-1);
// のような文が関数とみなされないようにするために使用する。
M2_KR_FUNC = 0x16, //!< K&Rスタイルの関数定義を調査する。
M2_AFTER_ITEM = 0x10,
} nMode2 = M2_NORMAL;
// char szFuncName[256]; // 関数名
const int nNamespaceNestMax = 32; //!< ネスト可能なネームスペース、クラス等の最大数
int nNamespaceLen[nNamespaceNestMax+1]; //!< ネームスペース全体の長さ
const int nNamespaceLenMax = 512; //!< 最大のネームスペース全体の長さ
char szNamespace[nNamespaceLenMax]; //!< 現在のネームスペース(終端が\0になっているとは限らないので注意)
const int nItemNameLenMax = 256;
char szItemName[nItemNameLenMax]; //!< すぐ前の 関数名 or クラス名 or 構造体名 or 共用体名 or 列挙体名 or ネームスペース名
// 例えば下のコードの←の部分での
// szNamespaceは"Namespace\ClassName\"
// nMamespaceLenは{10,20}
// nNestLevel_globalは2となる。
//
// namespace Namespace{
// class ClassName{
// ←
// }}
int nItemLine; //!< すぐ前の 関数 or クラス or 構造体 or 共用体 or 列挙体 or ネームスペースのある行
int nItemFuncId;
// int nFuncLine;
// int nFuncId;
// int nFuncNum; // 使っていないようなので削除
// 2002/10/27 frozen ここまで
// Mar. 4, 2001 genta
// bool bCppInitSkip; // C++のメンバー変数、親クラスの初期化子をSKIP // 2002/10/27 frozen nMode2の機能で代用
szWordPrev[0] = '\0';
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -