1. 程式人生 > >GCC-3.4.6原始碼學習筆記(128)

GCC-3.4.6原始碼學習筆記(128)

5.12.5. 第三個例子

現在我們已經有了“ SmallObject ”的定義,那麼我們使用下面的“ main ”函式來使用這個類,從中看一下將會產生怎樣的中間樹。

using namespace Loki;

int main ()

{

SmallObject<> object_;

return 1;
}

5.12.5.1. using 指示

假定這個“ main ”函式在另一個原始檔中,它也構成一個編譯單元,因此解析器由以下呼叫開始, cp_parser_translation_unit à cp_parser_declaration_seq_opt

,其中的 WHILE 迴圈將依次處理語句。

對於第一個是 using 指示的語句,呼叫棧進一步延伸,從 cp_parser_declaration à cp_parser_block_declaration à cp_parser_using_directive à parse_using_directive à do_using_directive

3350 void

3352 {

3353 if (namespace == error_mark_node)

3354 return ;

3355

3356 my_friendly_assert (TREE_CODE (namespace) == NAMESPACE_DECL, 20050830);

3357

3358 if (building_stmt_tree ())

3359 add_stmt (build_stmt (USING_STMT, namespace));

3361

3362 if (!toplevel_bindings_p ())

3363 push_using_directive (namespace);

3364 else

3365 /* direct usage */

3367 }

如果 building_stmt_tree 是非 0 值,表示正在為函式、塊等結構產生語句,那麼 using 指示將有 USING_STMT 為之生成。這裡的實參 namespace 是相應的 NAMESPACE_DECL 。在 3362 行,如果最裡層的有效非類作用域是一個名字空間( using 指示不允許在類域中使用,但可以用在其方法作用域中), toplevel_bindings_p 返回非 0 值。例如:

namespace A {

int i;

}

class B {

int func() {

using namespace A;

return i;

}

};

對於用在名字空間域的那些 using 指示,在對應於該名字空間作用域的 NAMESPACE_DECL 節點中,域 DECL_NAMESPACE_USING 將是一個 tree_list ,通過 add_using_namespace 用來把這些 using 指示串接起來。

3275 static void

3276 add_using_namespace (tree user, tree used, bool indirect) in name-lookup.c

3277 {

3278 tree t;

3279 timevar_push (TV_NAME_LOOKUP);

3280 /* Using oneself is a no-op. */

3281 if (user == used)

3282 {

3283 timevar_pop (TV_NAME_LOOKUP);

3284 return ;

3285 }

3286 my_friendly_assert (TREE_CODE (user) == NAMESPACE_DECL, 380);

3287 my_friendly_assert (TREE_CODE (used) == NAMESPACE_DECL, 380);

3288 /* Check if we already have this. */

3290 t = purpose_member (used, DECL_NAMESPACE_USING (user));

3291 if (t != NULL_TREE)

3292 {

3293 if (!indirect)

3294 /* Promote to direct usage. */

3295 TREE_INDIRECT_USING (t) = 0;

3296 timevar_pop (TV_NAME_LOOKUP);

3297 return ;

3298 }

3299

3300 /* Add used to the user's using list. */

3301 DECL_NAMESPACE_USING (user)

3303 DECL_NAMESPACE_USING (user));

3304

3305 TREE_INDIRECT_USING (DECL_NAMESPACE_USING (user)) = indirect;

3306

3307 /* Add user to the used's users list. */

3308 DECL_NAMESPACE_USERS (used)

3309 = tree_cons (user, 0, DECL_NAMESPACE_USERS (used));

3310

3311 /* Recursively add all namespaces used. */

3312 for (t = DECL_NAMESPACE_USING (used); t; t = TREE_CHAIN (t))

3313 /* indirect usage */

3314

3315

3316 /* Tell everyone using us about the new used namespaces. */

3317 for (t = DECL_NAMESPACE_USERS (user); t; t = TREE_CHAIN (t))

3318

3319 timevar_pop (TV_NAME_LOOKUP);

3320 }

一節中,我們看到 using 指示的使用必須不能混淆名字空間的層次,在名字查詢時,前端將嚴格按照其層次進行搜尋。 add_using_namespace 需要記錄必要的層次資訊。這裡 namespace_ancestor 找出 ns1 ns2 最接近的公共祖先。看到所有的名字空間都有相同的公共祖先——全域性名字空間。(關於 add_using_namespace 生成的這個列表的使用,參考 )。

3194 static tree

3196 {

3197 timevar_push (TV_NAME_LOOKUP);

3198

3199 POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, ns1);

3200 POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP,

3201 namespace_ancestor (CP_DECL_CONTEXT (ns1), ns2));

3202 }

這裡引數 root 是當前名字空間,而 child 是由 using 指示指定的名字空間。那麼 is_ancestor 持續地從 child 開始獲取上下文,直到找到 root 或離開這棵樹。對於前一種情形, root child 的祖先,並且函式返回非 0 值;反之,函式返回 0

2502 bool

2503 is_ancestor (tree root, tree child) in name-lookup.c

2504 {

2505 my_friendly_assert ((TREE_CODE (root) == NAMESPACE_DECL

2506 || TREE_CODE (root) == FUNCTION_DECL

2507 || CLASS_TYPE_P (root)), 20030307);

2508 my_friendly_assert ((TREE_CODE (child) == NAMESPACE_DECL

2509 || CLASS_TYPE_P (child)),

2510 20030307);

2511

2512 /* The global namespace encloses everything. */

2513 if (root == global_namespace )

2514 return true;

2515

2516 while (true)

2517 {

2518 /* If we've run out of scopes, stop. */

2519 if (!child)

2520 return false;

2521 /* If we've reached the ROOT, it encloses CHILD. */

2522 if (root == child)

2523 return true;

2524 /* Go out one level. */

2525 if (TYPE_P (child))

2526 child = TYPE_NAME (child);

2527 child = DECL_CONTEXT (child);

2528 }

2529 }

那麼對於我們的例子,全域性名字空間在其 DECL_NAMESPACE_USERS 域串接了“ Loki ”。

5.12.5.2. Main() 的定義

5.12.5.2.1. 函式定義 宣告符部分

對於 main 函式, cp_parser_declaration 又一次呼叫 cp_parser_block_declaration à cp_parser_simple_declaration 。在我們的上下文中,引數 function_definition_allowed_p true ,這表示我們同時把一個函式定義( function-definition )識別作簡單宣告( simple-declaration )。

block-declaration 的語法如下:

block-declaration:

simple-declaration | asm-definition | namespace-alias-definition | using-declaration |

using-directive

GNU Extension:

block-declaration: __extension__ block-declaration | label-declaration

6370 static void

6372 bool statement_p)

6373 {

6374 cp_token *token1;

6375 int saved_pedantic;

6376

6377 /* Check for the `__extension__' keyword. */

6378 if (cp_parser_extension_opt (parser, &saved_pedantic))

6379 {

6386 }

6387

6388 /* Peek at the next token to figure out which kind of declaration is

6389 present. */

6391

6392 /* If the next keyword is `asm', we have an asm-definition. */

6393 if (token1->keyword == RID_ASM)

6394 {

6398 }

6399 /* If the next keyword is `namespace', we have a

6400 namespace-alias-definition. */

6401 else if (token1->keyword == RID_NAMESPACE)

6402 cp_parser_namespace_alias_definition (parser);

6403 /* If the next keyword is `using', we have either a

6404 using-declaration or a using-directive. */

6405 else if (token1->keyword == RID_USING)

6406 {

6419 }

6420 /* If the next keyword is `__label__' we have a label declaration. */

6421 else if (token1->keyword == RID_LABEL)

6422 {

6426 }

6427 /* Anything else must be a simple-declaration. */

6428 else

6430 }

simple-declaration 的語法是:

simple-declaration:

decl-specifier-seq [opt] init-declarator-list [opt] ;

init-declarator-list:

init-declarator | init-declarator-list , init-declarator

看到 simple-declaration 可能被包含在一個 block-declaraition 中,而該 block-declaraition 則可能在一個函式域或類方法域中,其中要求訪問控制,因此期望一個新的延遲訪問例項。而在 6475 行的 stop_deferring_access_checks 防止加入更多由 perform_or_defer_access_check 檢查的延遲訪問控制,不過對於 decl-specifier-seq init-declarator-list 訪問檢查都是需要的,因此稍後將通過 resume_deferring_access_checks 重新開始檢查。

6444 static void

6446 bool function_definition_allowed_p)

6447 {

6448 tree decl_specifiers;

6449 tree attributes;

6450 int declares_class_or_enum;

6451 bool saw_declarator;

6452

6453 /* Defer access checks until we know what is being declared; the

6454 checks for names appearing in the decl-specifier-seq should be

6455 done as if we were in the scope of the thing being declared. */

6457

6458 /* Parse the decl-specifier-seq. We have to keep track of whether

6459 or not the decl-specifier-seq declares a named class or

6460 enumeration type, since that is the only case in which the

6461 init-declarator-list is allowed to be empty.

6462

6463 [dcl.dcl]

6464

6465 I n a simple-declaration, the optional init-declarator-list can be

6466 omitted only when declaring a class or enumeration, that is when

6467 the decl-specifier-seq contains either a class-specifier, an

6468 elaborated-type-specifier, or an enum-specifier. */

6469 decl_specifiers

6470 = cp_parser_decl_specifier_seq (parser,

6471 CP_PARSER_FLAGS_OPTIONAL,

6472 &attributes,

6473 &declares_class_or_enum);

6474 /* We no longer need to defer access checks. */

6475 stop_deferring_access_checks ();

6476

6477 /* In a block scope, a valid declaration must always have a

6478 decl-specifier-seq. By not trying to parse declarators, we can

6479 resolve the declaration/expression ambiguity more quickly. */

6480 if (!function_definition_allowed_p && !decl_specifiers)

6481 {

6482 cp_parser_error (parser, "expected declaration");

6483 goto done;

6484 }

6485

6486 /* If the next two tokens are both identifiers, the code is

6487 erroneous. The usual cause of this situation is code like:

6488

6489 T t;

6490

6491 where "T" should name a type -- but does not. */

6493 {

6494 /* If parsing tentatively, we should commit; we really are

6495 looking at a declaration. */

6497 /* Give up. */

6498 goto done;

6499 }

我們前面已經看到, cp_parser_decl_specifier_seq 將解析函式的返回型別;那麼在這裡 decl_specifiers 是一個 tree_list ,其中的 TREE_VALUE 域指向 integer_type_node 節點。注意一個函式定義可能沒有返回型別(它預設為 int )。

1950 static bool

1952 {

1953 /* If the next two tokens are both identifiers, the code is

1954 erroneous. The usual cause of this situation is code like:

1955

1956 T t;

1957

1958 where "T" should name a type -- but does not. */

1960 && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_NAME)

1961 {

1962 tree name;

1963

1964 /* If parsing tentatively, we should commit; we really are

1965 looking at a declaration. */

1966 /* Consume the first identifier. */

1968 /* Issue an error message. */

1969 error ("`%s' does not name a type", IDENTIFIER_POINTER (name));

1970 /* If we're in a template class, it's possible that the user was

1971 referring to a type from a base class. For example:

1972

1973 template <typename T> struct A { typedef T X; };

1974 template <typename T> struct B : public A<T> { X x; };

1975

1976 The user should have said "typename A<T>::X". */

1978 {

1979 tree b;

1980

1981 for (b = TREE_CHAIN (TYPE_BINFO (current_class_type ));

1982 b;

1983 b = TREE_CHAIN (b))

1984 {

1985 tree base_type = BINFO_TYPE (b);

1986 if (CLASS_TYPE_P (base_type)

1988 {

1989 tree field;

1990 /* Go from a particular instantiation of the

1991 template (which will have an empty TYPE_FIELDs),

1992 to the main version. */

1993 base_type = CLASSTYPE_PRIMARY_TEMPLATE_TYPE (base_type);

1994 for (field = TYPE_FIELDS (base_type);

1995 field;

1996 field = TREE_CHAIN (field))

1997 if (TREE_CODE (field) == TYPE_DECL

1998 && DECL_NAME (field) == name)

1999 {

2000 error ("(perhaps `typename %T::%s' was intended)",

2001 BINFO_TYPE (b), IDENTIFIER_POINTER (name));

2002 break ;

2003 }

2004 if (field)

2005 break ;

2006 }

2007 }

2008 }

2009 /* Skip to the end of the declaration; there's no point in

2010 trying to process it. */

2012

2013 return true;

2014 }

2015

2016 return false;

2017 }

作為正確的形式, decl-specifier-seq 的核心部分應該命名一個型別。通過名字查詢規則找到的該型別將被返回給 decl-specifiers ;而如果沒有找到適合的型別,這個符號保持為識別符號,那麼 cp_parser_diagnose_invalid_type_name 診斷這個錯誤情況,並給出診斷訊息。

cp_parser_simple_declaration (continue)

6501 /* If we have seen at least one decl-specifier, and the next token

6502 is not a parenthesis, then we must be looking at a declaration.

6503 (After "int (" we might be looking at a functional cast.) */

相關推薦

GCC-3.4.6原始碼學習筆記128

5.12.5. 第三個例子 現在我們已經有了“ SmallObject ”的定義,那麼我們使用下面的“ main ”函式來使用這個類,從中看一下將會產生怎樣的中間樹。 using namespace Loki; int main () { SmallObj

GCC-3.4.6原始碼學習筆記 當前目錄

參考文獻準備工作GCC的架構前端1.概覽1.1. 前端中樹的表達形式1.1.2. tree_code —— 樹節點的ID1.1.3.1.  節點大小的確定1.1.3.2.  記憶體分配1.2.1.  機器模式的概念[2]1.2.2.1. 初始化臨時的size_t節點1.2.2

Solr 6.7學習筆記02-- 配置文件 managed-schema (schema.xml) - filter5

schema load lis field folding factor 文件 iter tap 自定義fieldType時,通常還會用到filter。filter必須跟在tokenizer或其它filter之後。如: <fieldType> <

Spring原始碼學習筆記 bean是怎麼生成的

bean 實在 bean 重新整理過程中產生的,首先我們看下 bean 的重新整理方法。下面是 AbstractApplicationContext 的 refresh 方法。 @Override public void refresh() throws

spring 原始碼學習筆記事務管理

spring 事務管理會幫我們自動管理資料庫的事務,沒讀原始碼前覺得很神祕,讀了原始碼發現原理還是很簡單的。 本質上還是用的 jdbc 的事務管理。spring 在呼叫某個方法前,判斷是否需要事務,如果需要,則呼叫 con.setAutoCommit(false);//開

比特幣原始碼學習筆記

第二章 本章繼上一章交易建立之後介紹比特幣客戶端序列化資料的過程。 比特幣客戶端所有的序列化函式均在seriliaze.h中實現。其中,CDataStream類是資料序列化的核心結構。 CDataStream CDataStream擁有一個字元類容器用來存放序列化之後的資料

作業系統精髓與設計原理(原書第6版)——學習筆記8

2.4 現代作業系統的特徵 現代作業系統針對硬體中的新發展、新的應用程式和新的安全威脅。促使作業系統發展的硬體因素主要有: 多處理器的計算機系統 高速增長的機器速度 高速網路連線

作業系統精髓與設計原理(原書第6版)——學習筆記12

 3.2.3 五狀態模型 如果所有程序都做好了執行準備,則圖3.5b所給出的排隊規則是有效的。佇列是“先進先出”(FIFO)的表,對於可執行的程序處理器以一種輪轉方式操作(依次給佇列中的每個程

Hadoop HDFS原始碼學習筆記

一、首先根據HDFS的API寫一段程式,然後是用Eclipse進行debug 單步跟蹤,從而檢視原始碼執行流程: import java.net.URI; import org.apache.hadoop.conf.Configuration; import org.a

比特幣原始碼學習筆記

https://github.com/trottier/original-bitcoin 前言 從事區塊鏈的開發,不瞭解其底層核心技術是不夠的。許多人在看了比特幣白皮書之後仍然不清楚比特幣是怎樣實現的,因為比特幣的原始碼設計精巧,有許多設計白皮書未曾提及,加上本身

作業系統精髓與設計原理(原書第6版)——學習筆記2

 1.3.1 取指令和執行指令 指令暫存器(InstructionRegister,IR)放置取到的指令。指令中包含確定處理器要執行的操作位,處理器解釋指令並執行對應的操作。大體上,這些操作可

OBS原始碼學習筆記

obs-app.cpp是main入口檔案,然後通過load_debug_privilege函式,修改了下程序的許可權,呼叫base_set_crash_handler設定全域性的crash_handler,crash_param;設定def_log_handler函式作為日誌列印函式;接下來的判斷命令列引數,

Spring原始碼學習筆記AOP實現

Spring-AOP入口 <aop:aspectj-autoproxy /> 這一段程式碼,是實現AOP的具體入口,發現不是bean標籤則會使用不同的類進行解析,http\://www.springframework.org/sc

ES[7.6.x]學習筆記IK中文分詞器

在上一節中,我們給大家介紹了ES的分析器,我相信大家對ES的全文搜尋已經有了深刻的印象。分析器包含3個部分:字元過濾器、分詞器、分詞過濾器。在上一節的例子,大家發現了,都是英文的例子,是吧?因為ES是外國人寫的嘛,中國如果要在這方面趕上來,還是需要螢幕前的小夥伴們的~ 英文呢,我們可以按照空格將一句話、一

ES[7.6.x]學習筆記資料的增刪改

在前面幾節的內容中,我們學習索引、欄位對映、分析器等,這些都是使用ES的基礎,就像在資料庫中建立表一樣,基礎工作做好以後,我們就要真正的使用它了,這一節我們要看看怎麼向索引裡寫入資料、修改資料、刪除資料,至於搜尋嘛,因為ES的主要功能就是搜尋,所以搜尋的相關功能我們後面會展開講。 ## Document的建

ES[7.6.x]學習筆記搜尋

搜尋是ES最最核心的內容,沒有之一。前面章節的內容,索引、動態對映、分詞器等都是鋪墊,最重要的就是最後點選搜尋這一下。下面我們就看看點選搜尋這一下的背後,都做了哪些事情。 ## 分數(score) ES的搜尋結果是按照相關分數的高低進行排序的,咦?! 怎麼沒說搜尋先說搜尋結果的排序了?咱們這裡先把這個概念

Python 3.6學習筆記

示例 ror 功能 put -m 但是 對象 初始化 absolut 開始之前 基礎示例 Python語法基礎,python語法比較簡單,采用縮緊方式。 # print absolute value of a integer a = 100 if a >= 0:

C# EMGU 3.4.1學習筆記示例程式:霍夫圓變換HoughCircles函式

霍夫圓變換的基本思路是認為影象上每一個非零畫素點都有可能是一個潛在的圓上的一點,跟霍夫線變換一樣,也是通過投票,生成累積座標平面,設定一個累積權重來定位圓。 在笛卡爾座標系中圓的方程為: 其中(a,b)是圓心,r是半徑,也可以表述為: 即: 所以在ab

C# EMGU 3.4.1學習筆記XML和YAML檔案的寫入

以下是《OpenCV3程式設計入門》中5.6.3的示例程式的C# + EMGU 3.4.1版,和C++程式相比,有如下幾點不同: 1. 使用Matrix<>儲存多維陣列,多維陣列的各維需要使用{}擴起來,之間用逗號分隔; 2. C#中無法使用<<和

OpenCV學習筆記OpenCV 3.4.1 + VS2017 配置

對於EmguCV3.4.1的配置花了我兩天的時間,本來導師要求配置這個但是測試的時候有一個報錯資訊。為此我參考了各大部落格,無論是調debuger,還是x64,x86檔案的拷貝,都居然是失敗,無語死了,真的想吐槽。一怒之下,還是裝起C++的opencv3.4.1吧,硬著頭皮上