C语言编译器开发之旅(一):词法分析扫描器
本节我们先从一个简易的可以识别四则运算和整数值的词法分析扫描器开始。它实现的功能也很简单,就是读取我们给定的文件,并识别出文件中的token将其输出。
这个简易的扫描器支持的词法元素只有五个:
- 四个基本的算术运算符:
+、-、*、/ - 十进制整数
我们需要事先定义好每一个token,使用枚举类型来表示:
//defs.h
// Tokens
enum {
T_PLUS, T_MINUS, T_STAR, T_SLASH, T_INTLIT
};
在扫描到token后将其存储在一个如下的结构体中,当标记是 T_INTLIT(即整数文字)时,该intvalue 字段将保存我们扫描的整数值:
//defs.h
// Token structure
struct token {
int token;
int intvalue;
};
我们现在假定有一个文件,其内部的的代码就是一个四则运算表达式:
2 + 34 * 5 - 8 / 3
我们要实现的是读取他的每一个有效字符并输出,就像这样:
Token intlit, value 2
Token +
Token intlit, value 34
Token *
Token intlit, value 5
Token -
Token intlit, value 8
Token /
Token intlit, value 3
我们看到了最终要实现的目标,让我们来一步步分析需要的功能。
- 首先我们需要一个逐字符的读出文件中的内容并返回的函数。当我们在输入流中读的太远时,需要将读取到的字符放回(如上例当读到数字时,因无法直接获取数字是否结束,只能循环读取,当读到第一个非数字字符时则判定该十进制数读取结束,需将该十进制数返回并将读取的非数字字符放回),记录行号的的功能也是在这里实现。
// Get the next character from the input file.
static int next(void) {
int c;
if (Putback) { // Use the character put
c = Putback; // back if there is one
Putback = 0;
return c;
}
c = fgetc(Infile); // Read from input file
if ('\n' == c)
Line++; // Increment line count
return c;
}
- 我们只需要有效字符,所以需要去除空白字符的功能
// Skip past input that we don't need to deal with,
// i.e. whitespace, newlines. Return the first
// character we do need to deal with.
static int skip(void) {
int c;
c = next();
while (' ' == c || '\t' == c || '\n' == c || '\r' == c || '\f' == c) {
c = next();
}
return (c);
}
- 当读到的是数字的时候,怎么确定数字有多少位呢?所以我们需要一个专门处理数字的函数。
// Return the position of character c
// in string s, or -1 if c not found
static int chrpos(char *s, int c) {
char *p;
p = strchr(s, c);
return (p ? p - s : -1);
}
// Scan and return an integer literal
// value from the input file. Store
// the value as a string in Text.
static int scanint(int c) {
int k, val = 0;
// Convert each character into an int value
while ((k = chrpos("0123456789", c)) >= 0) {
val = val * 10 + k;
c = next();
}
// We hit a non-integer character, put it back.
putback(c);
return val;
}
所以现在我们可以在跳过空格的同时读取字符;如果我们读到一个字符太远,我们也可以放回一个字符。我们现在可以编写我们的第一个词法扫描器:
int scan(struct token *t) {
int c;
// Skip whitespace
c = skip();
// Determine the token based on
// the input character
switch (c) {
case EOF:
return (0);
case '+':
t->token = T_PLUS;
break;
case '-':
t->token = T_MINUS;
break;
case '*':
t->token = T_STAR;
break;
case '/':
t->token = T_SLASH;
break;
default:
// If it's a digit, scan the
// literal integer value in
if (isdigit(c)) {
t->intvalue = scanint(c);
t->token = T_INTLIT;
break;
}
printf("Unrecognised character %c on line %d\n", c, Line);
exit(1);
}
// We found a token
return (1);
}
现在我们可以读取token并将其返回。
main() 函数打开一个文件,然后扫描它的令牌:
void main(int argc, char *argv[]) {
...
init();
...
Infile = fopen(argv[1], "r");
...
scanfile();
exit(0);
}
并scanfile()在有新token时循环并打印出token的详细信息:
// List of printable tokens
char *tokstr[] = { "+", "-", "*", "/", "intlit" };
// Loop scanning in all the tokens in the input file.
// Print out details of each token found.
static void scanfile() {
struct token T;
while (scan(&T)) {
printf("Token %s", tokstr[T.token]);
if (T.token == T_INTLIT)
printf(", value %d", T.intvalue);
printf("\n");
}
}
我们本节的内容就到此为止。下一部分中,我们将构建一个解析器来解释我们输入文件的语法,并计算并打印出每个文件的最终值。
本文Github地址:https://github.com/Shaw9379/acwj/tree/master/01_Scanner
C语言编译器开发之旅(一):词法分析扫描器的更多相关文章
- C语言编译器开发之旅(开篇)
编译器写作之旅 最近在Github上看到一个十分有趣的项目acwj(A Compiler Writing Journey),一个用C语言编写编译器的项目.身为一个程序员,这在我看来是一件十分酷的事 ...
- C语言编译器开发之旅(二):解析器
本节是我们这个编译器系列的第二节,进入语法分析与语义分析的部分解.在本节我们会编写一个简单的解析器. 解析器的主要功能分为两个部分: 识别输入的语法元素生成AST(Abstract Syntax Tr ...
- JVM 平台上的各种语言的开发指南
JVM 平台上的各种语言的开发指南 为什么我们需要如此多的JVM语言? 在2013年你可以有50中JVM语言的选择来用于你的下一个项目.尽管你可以说出一大打的名字,你会准备为你的下一个项目选择一种新的 ...
- 第一个C语言编译器是怎样编写的?
首先向C语言之父Dennis MacAlistair Ritchie致敬! 当今几乎所有的实用的编译器/解释器(以下统称编译器)都是用C语言编写的,有一些语言比如Clojure,Jython等是基于J ...
- 【转】自己动手写SC语言编译器
自序 编译原理与技术的一整套理论在整个计算机科学领域占有相当重要的地位,学习它对程序设计人员有很大的帮助.我们考究历史会发现那些人人称颂的程序设 计大师都是编译领域的高手,像写出BASIC语言的BIL ...
- 嵌入式C语言编译器
GCC与gcc: 初识编译器: 扩展问题: 如何理解“多语言混合开发”? 参考: 狄泰软件学院唐佐林视频教程
- 跨平台、跨语言应用开发,Elements 介绍
目录 1,Elements 介绍 2,Elements 版本 3,Elements 能干嘛 4,Elements IDES 5,Elements 工具 1,Elements 介绍 RemObject ...
- C语言编译器和IDE的选择
什么是编译器: CPU只认识几百个二进制形式的指令,C语言对CPU而言简直就是天书.C语言是用固定的词汇与格式组织起来,简单直观,程序员容易识别和理解. 这时候就需要一个工具,将C语言代码转换成CPU ...
- 李洪强漫谈iOS开发[C语言-003]-开发概述程序设计语言
李洪强iOS开发之程序设计语言 printf 是打印的意思- 格式化输出 f: format 格式化 C语言编译器 编译器的功能就是将高级语言的源代码,翻译成机器可以识别的二进制文件就是可执 行文件- ...
随机推荐
- 一文上手Python3
案例参考:廖雪峰--Python教程 基础知识 基本数据类型 用type()来判断数据类型: In [1]: type(1) Out[1]: int In [2]: type(1.0) O ...
- 构建基于表单配置的 Jenkins 测试项目(接口、UI、APP、Jmeter)
1. 第一个 hello world 项目 2. 构建自动触发的项目(接口测试) 1)新建测试项目(执行测试脚本) 2)新建 Maven 打包项目 3)手动执行构建 4)修改 Web 工程代码并 pu ...
- Vue.js入门及其常用指令
一.Vue框架 https://cn.vuejs.org/ 官网 前端领域有三大框架 Angular诞生于2009年,是由谷歌公司创建出来的框架: React诞生于2013年,是由facebook公司 ...
- 数据结构(5):Java实现二叉树
二叉树图: package com.test.Sort; import java.util.ArrayList; import java.util.LinkedList; public class B ...
- 1.6.3- HTML有序列表 ol元素
代码如下: 浏览器打开: 总结:
- HIT手 | 机械电气构造简述和微分运动学及静力学的简单推导
机械结构电气构造简述 HIT手有四个手指,每个手指4个关节,其中第一和第二个关节正交,第三和第四个关节机械耦合,故只有3个自由度,另外大拇指多了一个相对手掌运动的自由度,故一只手掌总共有13各个自 ...
- hdu2067 简单dp或者记忆化搜索
题意: 小兔的棋盘 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Sub ...
- hdu3793 判断对称(水题)
题意: 给你一个串,问你这个串是不是关于某个字母对称的,这个串是一个首位相接的圆. 思路: 水题,直接枚举每一个为对称点试一下就行了,不解释了. #include<std ...
- poj1509最小表示法
题意: 给你一个循环串,然后找到一个位置,使得从这个位置开始的整个串字典序最小. 思路: 最小表示法的建档应用,最小表示法很好理解,就点贪心的意思,一开始我们枚举两个起点i,j ...
- PHP Tips
开启x_debug,使用var_dump()的显示效果会更好,同时错误也很更详细.