小白说编译原理-2-lex基本用法

本文介绍了如何使用lex创建词法分析器,包括lex的基本用法、样例解析及功能说明。通过lex.l文件定义规则,lex编译器生成lex.h和lex.cpp,最终编译成可执行程序,实现对输入流的字符序列处理。

前言

这个编译原理是一个系列,系列地址为: https://blog.csdn.net/lpstudy/article/category/937055
考虑到很多小伙伴咨询代码的问题,现把链接发出来:https://github.com/lpstudy/compile
这个链接里面具有这个系列所有的VS工程和代码,工程是按照系列中的一个教程环境配置6来配置的,不过lib我好像没有上传到github。
如果大家发现任何问题,可以在github或者csdn,我有空的时候完善一下,争取做到下载github工程即可跑。
#lex词法分析器

概述

1,使用lex语言书写一套正规表达式的规则,命名为lex.l
2,由lex编译器负责将lex.l编译为lex.h和lex.cpp,这两个文件包含了lex定义的规则
3,再使用标准的c++编译器即可以将lex.cpp编译生成可执行程序lex.exe
4,lex.exe识别输入流,并将其转换为字符序列,并执行相应的操作(在lex.l中定义)

lex样例

%{
/***/
%}

// lexical analyser name
%name lexer

%%
[ \t]+ {printf(" ");}
\n|.    {printf("%s", yytext);}
%%

int main()
{
//create a lexer, and call the lex function.
//it will read from stdin and parser the tokens.
 YYLEXERNAME lexer;
 if(lexer.yycreate()){
	 lexer.yylex();
 }
}

#简单的语法结构
声明段:

		 %{
				c++语言代码,一般为头文件包含,以及变量声明,定义。
				注意:代码会被原样copy到生成的代码文件中。
		 %}
		 正规定义

规则段:

%%
	用户定义的转换规则
	P1 {action}
	P1表示正规表达式,action为相应的执行动作。
%%

子程序段:

	主要包含用户子程序代码,代码会被原样copy到生成的代码文件中。

#解析说明例子

  1. %name lexer
    这是说明词法分析器的类名字为lexer,最后生成的代码中会有 #define YYLEXERNAME lexer。
  2. [ \t]+ {printf(" ");}
    前面是表达式,后面{}中是进行的动作。 [ \t]+表示连续的空白字符(空格,tab), 进行的语义动作是打印一个空格。
  3. \n|. {printf("%s", yytext);}
    其他任意字符,原样打印。因为.无法表达\n这样的字符,所以使用|的或操作。
  4. 功能说明
    将连续的空格或者tab压缩为一个空格,其他字符原样输出。

lex样例2,解析token

%{
#include <iostream>
using namespace std;
enum{
LT,  EQ, GT, IF, ELSE, ID, NUMBER, PLUS, MINUS, TIMES, OVER, INT, DOUBLE,CHAR
};
const char* tokenStr[] = {"LT",  "EQ", "GT", "IF", "ELSE", "ID", "NUMBER", "PLUS", "MINUS", "TIMES", "OVER", "INT", "DOUBLE","CHAR"
};
static void print_token(int token, char* lex);

%}

%name lexer

delim [ \t\n]
ws    {delim}+
letter [a-zA-Z]
digit [0-9]
id    {letter}({letter}|{digit})*
/* can support 12.34 */
number {digit}+(\.{digit}+)?


%%
{ws} {/* do nothing */}
"int"  {print_token(INT, yytext);}
"double"  {print_token(DOUBLE, yytext);}
"char"  {print_token(CHAR, yytext);}

"+"         {print_token(PLUS, yytext); }
"-"         {print_token(MINUS, yytext);}
"*"         {print_token(TIMES, yytext);}
"/"         {print_token(OVER, yytext); }
{id}        {print_token(ID, yytext);}
{number}    {print_token(NUMBER, yytext);}
%%




static void print_token(int token, char* lex)
{
	cout<<"token:" << tokenStr[token]<<" "<<"lex:"<<lex<<endl;
}

int main()
{
//create a lexer, and call the lex function.
//it will read from stdin and parser the tokens.
 YYLEXERNAME lexer;
 if(lexer.yycreate()){
	 lexer.yylex();
 }
}

样例2说明

  1. 最前面的%{ … %}内的为变量以及函数声明部分
  2. %name lexer 定义词法分析器的名字
  3. delim [ \t\n] 这些是正规的定义,通过递归的定义可以定义更复杂的正规式,例如id和number的定义
  4. %% … %% 正规表达式与执行的动作的绑定
  5. 最后的函数实现代码为整个驱动程序,它读取用户输入,并解析token,执行action

下节内容

yacc语法程序,能够实现一个简单的四则运算。

本人lpstudy,转载请注明出处: http://blog.csdn.net/lpstudy/article/details/51224869

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值