gcc编译器分析

gcc编译器分析

    • 参考
    • 词法分析
    • 语法分析
      • 预读一个符号
      • 语法分析函数调用关系
      • 重点函数分析
        • c_parse_file
        • c_parser_translation_unit

参考

《gcc源码分析》

词法分析

词法分析的过程就是将源代码识别成一个一个的词法符号,并在词法分析的过程中创建一些树节点,用来保存某些词法符号的值(value)。这些需要创建树节点的词法符号主要包括标识符(CPP_NAME)、关键字(CPP_KEYWORD)、数值(CPP_NUMBER)常量等。在后续的语法分析过程中,会将这些AST节点(或者AST子树)根据语法规则链接起来,形成某个函数完整的AST结构。

语法分析

语法分析就是,提前预读两个词法符号的自顶向下的语法推导过程:包括提前预读词法符号,语法分析状态以及上下文信息。

这些信息通常将保存在c_parser 这个结构体当中:

/* A parser structure recording information about the state andcontext of parsing.  Includes lexer information with up to twotokens of look-ahead; more are not needed for C.  */
typedef struct c_parser GTY(())
{/* The look-ahead tokens.  */c_token tokens[2];/* How many look-ahead tokens are available (0, 1 or 2).  */short tokens_avail;/* True if a syntax error is being recovered from; false otherwise.c_parser_error sets this flag.  It should clear this flag whenenough tokens have been consumed to recover from the error.  */BOOL_BITFIELD error : 1;/* True if we're processing a pragma, and shouldn't automaticallyconsume CPP_PRAGMA_EOL.  */BOOL_BITFIELD in_pragma : 1;/* True if we're parsing the outermost block of an if statement.  */BOOL_BITFIELD in_if_block : 1;/* True if we want to lex an untranslated string.  */BOOL_BITFIELD lex_untranslated_string : 1;/* Objective-C specific parser/lexer information.  */BOOL_BITFIELD objc_pq_context : 1;/* The following flag is needed to contextualize Objective-C lexicalanalysis.  In some cases (e.g., 'int NSObject;'), it isundesirable to bind an identifier to an Objective-C class, evenif a class with that name exists.  */BOOL_BITFIELD objc_need_raw_identifier : 1;
} c_parser;

gcc对c语言进行语法分析的入口函数为c_parse_file :


/* Parse a single source file.  */void
c_parse_file (void)
{/* Use local storage to begin.  If the first token is a pragma, parse it.If it is #pragma GCC pch_preprocess, then this will load a PCH filewhich will cause garbage collection.  */c_parser tparser;memset (&tparser, 0, sizeof tparser);the_parser = &tparser;if (c_parser_peek_token (&tparser)->pragma_kind == PRAGMA_GCC_PCH_PREPROCESS)c_parser_pragma_pch_preprocess (&tparser);the_parser = GGC_NEW (c_parser);*the_parser = tparser;c_parser_translation_unit (the_parser);the_parser = NULL;
}

预读一个符号

预读一个符号,如果是PRAGMA_GCC_PCH_PREPROCESS,将进行编译的预处理工作,c_parser_pragma_pch_preprocess 为预处理函数。
c_parser_peek_token 会解析出一个token,这时会返回指向下个token的指针:

/* Return a pointer to the next token from PARSER, reading it in ifnecessary.  */static inline c_token *
c_parser_peek_token (c_parser *parser)
{if (parser->tokens_avail == 0){c_lex_one_token (parser, &parser->tokens[0]);parser->tokens_avail = 1;}return &parser->tokens[0];
}

解析一个单独的词法符号时,调用c_lex_one_token

/* Read in and lex a single token, storing it in *TOKEN.  */static void
c_lex_one_token (c_parser *parser, c_token *token)
{timevar_push (TV_LEX);token->type = c_lex_with_flags (&token->value, &token->location, NULL,(parser->lex_untranslated_string? C_LEX_STRING_NO_TRANSLATE : 0));token->id_kind = C_ID_NONE;token->keyword = RID_MAX;token->pragma_kind = PRAGMA_NONE;switch (token->type){case CPP_NAME:{tree decl;bool objc_force_identifier = parser->objc_need_raw_identifier;if (c_dialect_objc ())parser->objc_need_raw_identifier = false;if (C_IS_RESERVED_WORD (token->value)){enum rid rid_code = C_RID_CODE (token->value);if (rid_code == RID_CXX_COMPAT_WARN){warning_at (token->location,OPT_Wc___compat,"identifier %qs conflicts with C++ keyword",IDENTIFIER_POINTER (token->value));}else if (c_dialect_objc ()){if (!objc_is_reserved_word (token->value)&& (!OBJC_IS_PQ_KEYWORD (rid_code)|| parser->objc_pq_context)){/* Return the canonical spelling for this keyword.  */token->value = ridpointers[(int) rid_code];token->type = CPP_KEYWORD;token->keyword = rid_code;break;}}else{token->type = CPP_KEYWORD;token->keyword = rid_code;break;}}decl = lookup_name (token->value);if (decl){if (TREE_CODE (decl) == TYPE_DECL){token->id_kind = C_ID_TYPENAME;break;}}else if (c_dialect_objc ()){tree objc_interface_decl = objc_is_class_name (token->value);/* Objective-C class names are in the same namespace asvariables and typedefs, and hence are shadowed by localdeclarations.  */if (objc_interface_decl&& (global_bindings_p ()|| (!objc_force_identifier && !decl))){token->value = objc_interface_decl;token->id_kind = C_ID_CLASSNAME;break;}}token->id_kind = C_ID_ID;}break;case CPP_AT_NAME:/* This only happens in Objective-C; it must be a keyword.  */token->type = CPP_KEYWORD;token->keyword = C_RID_CODE (token->value);break;case CPP_COLON:case CPP_COMMA:case CPP_CLOSE_PAREN:case CPP_SEMICOLON:/* These tokens may affect the interpretation of any identifiersfollowing, if doing Objective-C.  */if (c_dialect_objc ())parser->objc_need_raw_identifier = false;break;case CPP_PRAGMA:/* We smuggled the cpp_token->u.pragma value in an INTEGER_CST.  */token->pragma_kind = (enum pragma_kind) TREE_INT_CST_LOW (token->value);token->value = NULL;break;default:break;}timevar_pop (TV_LEX);
}

语法分析函数调用关系

在这里插入图片描述

重点函数分析

c_parse_file

函数c_parse_filer如上所述,是C语法分析的入口函数,该函数首先对当前的词法符号进行判断,如果该符号的编译制导类型是PRAGMA_GCC_PCH_PREPROCESS,则调用函数c_parser_pragma_pch_preprocess对进行源代码的预处理,否则,调用函数c_parser_translation_unit()进行语法推导。

c_parser_translation_unit

这个函数是进行语法分析的主流程函数:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/832035.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

tomcat+nginx 动静分离

一、单机反向代理 7-1 7-2 测试 二、多机反向代理 1. 环境准备 机器IP地址服务7-1172.168.1.11nginx7-2172.168.1.12tomcat7-3172.168.1.13tomcat 2. 配置7-1 Nginx 服务器 vim /apps/nginx/conf/nginx.confhttp:upstream tomcat {server 172.168.1.12:8080;server …

探索设计模式的魅力:分布式模式让业务更高效、更安全、更稳定

​🌈 个人主页:danci_ 🔥 系列专栏:《设计模式》 💪🏻 制定明确可量化的目标,坚持默默的做事。 ✨欢迎加入探索分布式模式之旅✨ 在数字化时代,企业面临着前所未有的挑战和机遇。…

STM32开发笔记-新建标准库工程

1.STM32开发方式 STM32开发一般包括三种方式:基于寄存器开发、基于标准外设库开发、基于HAL库开发。 标准外设库是最基础的STM32开发方式,提供了一系列函数用于配置和控制STM32的外设,如GPIO、USART、SPI等。使用标准外设库需要手动编写代码…

(39)4.29数据结构(栈,队列和数组)栈

#include<stdlib.h> #include<stdio.h> #define MaxSize 10 #define Elemtype int 1.栈的基本概念 2.栈的基本操作 typedef struct { Elemtype data[MaxSize]; int top; }Sqstack;//初始化栈 void InitStack(Sqstack& S) { S.top -1; //初始化…

Golang日志管理:使用log/slog实现高级功能和性能优化

Golang日志管理&#xff1a;使用log/slog实现高级功能和性能优化 简介基础使用初始化和配置日志级别 高级技巧自定义日志格式器条件日志处理 实战案例场景一&#xff1a;API请求日志记录场景二&#xff1a;错误跟踪和用户通知 性能优化优化日志记录的性能异步日志处理选择合适的…

Vue的项目启动指令分析

通过Vue CLI脚手架创建的项目&#xff0c;默认的启动项目方式是 npm run serve 这里的serve是可以修改的。 在创建的项目目录中&#xff0c;找到package.json 双击打开&#xff0c;找到scripts部分 在scripts部分&#xff0c;有一个"serve"键值对&#xff0c;这里的…

机器学习-K近邻算法(KNN)

目录 什么是KNN算法 图解KNN基本算法 &#xff08;1&#xff09;k近邻算法中k的选取 &#xff08;2&#xff09;距离函数 &#xff08;3&#xff09;归一化处理 &#xff08;4&#xff09;概率kNN KNN算法的优缺点 优势 缺点 KNN算法总结 什么是KNN算法 k近邻算法&…

[Spring Cloud] (6)gateway整体加解密

文章目录 简述整体效果后端增加配置nacos增加配置GlobalConfig 添加请求整体解密拦截器DecryptionFilter添加响应整体解密拦截器EncryptionFilter 前端请求拦截器添加整体加密逻辑请求头中添加sessionId 响应拦截器添加整体解密逻辑 简述 本文网关gateway&#xff0c;微服务&a…

[C语言]指针进阶详解

指针是C语言的精髓所以内容可能会比较多&#xff0c;需要我们认真学习 目录 1、字符指针 2、指针数组 3、数组指针 3.1数组指针的定义 3.2&数组名vs数组名 3.3数组指针的使用 4、数组传参和指针传参 4.1一维数组传参 4.2二维数组传参 4.3一级指针传参 4.4二级指…

学习如何使用PyQt5实现notebook功能

百度搜索“pyqt5中notebook控件”&#xff0c;AI自动生成相应例子的代码。在 PyQt5 中&#xff0c;QTabWidget 类被用作 Notebook 控件。以下是一个简单的示例&#xff0c;展示如何创建一个带有两个标签的 Notebook 控件&#xff0c;并在每个标签中放置一些文本。 import sys f…

45. UE5 RPG 增加角色受击反馈

在前面的文章中&#xff0c;我们实现了对敌人的属性的初始化&#xff0c;现在敌人也拥有的自己的属性值&#xff0c;技能击中敌人后&#xff0c;也能够实现血量的减少。 现在还需要的就是在技能击中敌人后&#xff0c;需要敌人进行一些击中反馈&#xff0c;比如敌人被技能击中后…

使用macof发起MAC地址泛洪攻击

使用macof发起MAC地址泛洪攻击 MAC地址泛洪攻击原理&#xff1a; MAC地址泛洪攻击是一种针对交换机的攻击方式&#xff0c;目的是监听同一局域网中用户的通信数据。交换机的工作核心&#xff1a;端口- MAC地址映射表。这张表记录了交换机每个端口和与之相连的主机MAC地址之间…

Spring Boot与JSP的浪漫邂逅:轻松构建动态Web应用的秘诀

本文介绍 Spring Boot 集成 JSP。 1、pom.xml 增加对 JSP 的支持 Spring Boot 的默认视图支持是 Thymeleaf 模板引擎&#xff0c;如果想要使用 JSP 页面&#xff0c;需要配置 servlet 依赖和 tomcat 的支持。 在 pom.xml 文件中增加如下代码&#xff1a; <!-- servlet依赖 -…

(六)SQL系列练习题(下)#CDA学习打卡

目录 三. 查询信息 16&#xff09;检索"1"课程分数小于60&#xff0c;按分数降序排列的学生信息​ 17&#xff09;*按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩 18&#xff09;*查询各科成绩最高分、最低分和平均分 19&#xff09;*按各科成绩…

Apache和Nginx的区别以及如何选择

近来遇到一些客户需要lnmp环境的虚拟主机&#xff0c;但是Hostease这边的虚拟主机都是基于Apache的&#xff0c;尽管二者是不同的服务器软件&#xff0c;但是大多数情况下&#xff0c;通过适当的配置和调整两者程序也是可以兼容的。 目前市面上有许多Web服务器软件&#xff0c;…

rust使用Atomic创建全局变量和使用

Mutex用起来简单&#xff0c;但是无法并发读&#xff0c;RwLock可以并发读&#xff0c;但是使用场景较为受限且性能不够&#xff0c;那么有没有一种全能性选手呢&#xff1f; 欢迎我们的Atomic闪亮登场。 从 Rust1.34 版本后&#xff0c;就正式支持原子类型。原子指的是一系列…

HCIP第二节

OSPF&#xff1a;开放式最短路径协议&#xff08;属于IGP-内部网关路由协议&#xff09; 优点&#xff1a;相比与静态可以实时收敛 更新方式&#xff1a;触发更新&#xff1a;224.0.0.5/6 周期更新&#xff1a;30min 在华为设备欸中&#xff0c;默认ospf优先级是10&#…

对于子数组问题的动态规划

前言 先讲讲我对于这个问题的理解吧 当谈到解决子数组问题时&#xff0c;动态规划(DP)是一个强大的工具&#xff0c;它在处理各种算法挑战时发挥着重要作用。动态规划是一种思想&#xff0c;它通过将问题分解成更小的子问题并以一种递归的方式解决它们&#xff0c;然后利用这些…

500行代码实现贪吃蛇(1)

文章目录 目录1. Win32 API 介绍1.1 Win32 API1.2 控制台程序&#xff08;Console&#xff09;1.3 控制台屏幕上的坐标COORD1.4 [GetStdHandle](https://learn.microsoft.com/zh-cn/windows/console/getstdhandle)1.5 [GetConsoleCursorInfo](https://learn.microsoft.com/zh-c…

【论文阅读】Sparse is Enough in Scaling Transformers

Sparse is Enough in Scaling Transformers 论文地址摘要1 介绍2 相关工作模型压缩。模型修剪模型蒸馏。稀疏注意力。张量分解。稀疏前馈。 3 Sparse is Enough3.1 稀疏前馈层3.2 稀疏 QKV 层3.3 稀疏损失层。 4 长序列的稀疏性4.1 长序列架构4.2 内存效率的可逆性4.3 泛化的循…