用 C 语言使用 ragel

Ragel是个有限状态机编译器,它将基于正则表达式的状态机编译成传统语言(C,C++,D,Java,Ruby等)的解析器。

用Ragel可以很方便且很容易的写出各种FSM,也经常用作语法检测器。

Ragel State Machine Compiler

一个用C语言实现的例子:

#include <stdio.h>
#include <string.h>

%%{
    machine foo; #FSM 名称

    #定义动作
    action res_true {
        res=1;
    }
    action res_false {
        res=0;
    }
    action res_err {
        res=-1;
    }

    #FSM 起点
    main := ( ‘true‘0 @res_true | ‘false‘0 @res_false | any @res_err); 

    #写入 FSM 数据
    write data;
}%%

int GetRes(char *pbuf)
{
    int res;
    char *p=pbuf; //初始化 p 指向需要做 FSM 处理的数组起始地址
    char *pe=p+strlen(pbuf)+1; //初始化 pe 指向 p 的结束地址
    int cs; // cs 用来保存 FSM 运行中状态

    //写入初始化代码
    %%write init;

    //写入执行代码
    %%write exec;
    return res;
}

int main()
{
    int cs;
    char buf[256];
    while (scanf("%s",buf)) {
        printf("res=%d\n",GetRes(buf));
    }
    return 0;
}

编译

上面的代码还不能直接用gcc编译,需要先用ragel编译成C语言代码,再用gcc编译成可执行程序。

ragel -o main.c main.rl
gcc -o test main.c

上面例子实现的是把字符串"true" "false"转换成C语言1 0的形式,如果既不是"true"也不是"false"则结果为-1。

执行结果

输入

true

false

truefalse

输出

res=1

res=0

res=-1

基本语法

多行的FSM定义以 %%{ 开始 %%} 结束。单行的FSM定义在行首以 %% 开始。

machine foo; 状态机的名称。

action 定义匹配动作,动作内写入匹配后所要执行的代码。

上面代码有3个动作,分别是 res_true, res_false, res_err 用来得出结果 。

main := 正则表达式;  表示FSM起始点,匹配先从这里开始。

上面代码中( ‘true‘0 @res_true | ‘false‘0 @res_false | any @res_err)表示

(如果成功匹配 "true\0" 执行动作res_true) 或则 (如果成功匹配 "false\0" 执行动作res_false) 或则 (如果成功匹配 任意字符 执行动作res_err )

any是Ragel 的关键字,类似的还有

关键字 描述
any 所有字符.
ascii ascii字符.0~127
extend ascii扩展的字符.有符号-128~127或无符号0~255
alpha 字母.[a~z A~Z]
digit 数字.[0~9]
alnum 字母和数字.[a~z A~Z 0~9]
lower 小写字母.[a~z]
upper 大写字母.[A~Z]
xdigit 16进制数字.[0~9 a~f A~F]
cntrl 控制字符.0~31
graph 可视字符.[!-~]
print 可打印字符.[ -~]
punct 非字母数字可视字符.[!-/:[email protected][-‘{-~]
space 空白字符.[\t\v\f\n\r ]
zlen 空字符串.""
empty 空集.^any

%%write data; 写入FSM运行中需要的状态数据,可以放在任何地方,但必须要在 %%write exec 之上。

%%write init; 写入FSM的初始化代码,放在函数之内,需要先定义 int cs。

%%write exec; 写入FSM的执行代码,放在函数之内,需要先定义 char *p 和 char *pe。

结束语

虽然使用Ragel很轻松的解决平常我们 if else if 功能,而且效率也不错,但是会使生成的源代码和程序体积变大(19K生成30M源码),所以使用前还是需要考虑考虑。

更详细的使用说明可以在Ragel State Machine Compiler下载使用手册。

时间: 2024-10-12 11:05:14

用 C 语言使用 ragel的相关文章

C 语言资源大全中文版

C 语言资源大全中文版 我想很多程序员应该记得 GitHub 上有一个 Awesome - XXX 系列的资源整理.awesome-c 是 koz.ross 发起维护的 C 语言资源列表,内容包括了:构建系统.编译器.数据库.加密.初中高的教程/指南.书籍.库等等. Awesome 系列虽然挺全,但基本只对收录的资源做了极为简要的介绍,如果有更详细的中文介绍,对相应开发者的帮助会更大.这也是我们发起这个开源项目的初衷. 我们要做什么? 基于 awesome-c 列表,我们将对其中的各个资源项进行

使用R语言计算均值,方差等

R语言对于数值计算很方便,最近用到了计算方差,标准差的功能,特记录. 数据准备 height <- c(6.00, 5.92, 5.58, 5.92) 1 计算均值 mean(height) [1] 5.855 2 计算中位数 median(height) [1] 5.92 3 计算标准差 sd(height) [1] 0.1871719 4 计算方差 var(height) [1] 0.03503333 5 计算两个变量之间的相关系数 cor(height,log(height)) [1] 0

GCC在C语言中内嵌汇编 asm __volatile__ 【转】

转自:http://blog.csdn.net/pbymw8iwm/article/details/8227839 在内嵌汇编中,可以将C语言表达式指定为汇编指令的操作数,而且不用去管如何将C语言表达式的值读入哪个寄存器,以及如何将计算结果写回C 变量,你只要告诉程序中C语言表达式与汇编指令操作数之间的对应关系即可, GCC会自动插入代码完成必要的操作. 1.简单的内嵌汇编 例: __asm__ __volatile__("hlt"); "__asm__"表示后面的

C语言轻松高效学习方法之:多种方法实现

多种方法实现同一个功能,可以调动你学的所有知识去做,有助于你学的融会贯通. 下面举例来看: 实现功能:求一个整数的位数: 实现语言:C语言: 开发环境:Visual Studio 2017 如:3215是4位数 实现原理: 3215/10 = 321 ----1位数 321/10 = 32 ----又是1位数 32/10 = 3 ----又是1位数 3/10 = 0 ----又是1位数 共4位数,且终止计算条件是/10结果为0的时候: 根据这个原理,先写一个最笨的原始方法: 效果: 这种实现方案

轻松学习C语言编程的秘诀:总结+灵感

目前在准备一套C语言的学习教程,所以我这里就以C语言编程的学习来讲.注意,讲的是"轻松学习",那种不注重方法,拼命玩命的方式也有其效果,但不是我提倡的.我讲究的是在方式方法对头.适合你.减轻你学习负担和心里压力的前提下,才适当的抓紧时间. 因此,探索一种很好的学习方法就是我所研究的主要内容. 众所周知,学习C语言并非易事,要学好它更是难上加难.这和你期末考试背会几个题目的答案考上满分没多大关系,也就是说你考试满分也说明不了你学好.学精通了C语言.那么怎么才算学精通C语言?闭着眼睛对自己

详解go语言的array和slice 【二】

上一篇  详解go语言的array和slice [一]已经讲解过,array和slice的一些基本用法,使用array和slice时需要注意的地方,特别是slice需要注意的地方比较多.上一篇的最后讲解到创建新的slice时使用第三个索引来限制slice的容量,在操作新slice时,如果新slice的容量大于长度时,添加新元素依然后使源的相应元素改变.这一篇里我会讲解到如何避免这些问题,以及迭代.和做为方法参数方面的知识点. slice的长度和容量设置为同一个值 如果在创建新的slice时我们把

自动生成小学四则运算题目(C语言)

这个简易四则运算是我在百度上找的博主叫53余雅诗的一篇c语言代码,网址为http://www.cnblogs.com/ys1101/p/4368103.html,功能是可以选择加减乘除进行简易的四则运算,判断对错.我在VS2017上编译没有bug,因为功能只有整数运算,所以我在此基础上加了真分数的四则运算以及统计得分等,最后成功运行程序.我把我的源代码放在github上,地址为https://github.com/xiaofancheng/helloworld.

PAT 1009 说反话 C语言

给定一句英语,要求你编写程序,将句中所有单词的顺序颠倒输出. 输入格式:测试输入包含一个测试用例,在一行内给出总长度不超过80的字符串.字符串由若干单词和若干空格组成,其中单词是由英文字母(大小写有区分)组成的字符串,单词之间用1个空格分开,输入保证句子末尾没有多余的空格. 输出格式:每个测试用例的输出占一行,输出倒序后的句子. 输入样例: Hello World Here I Come 输出样例: Come I Here World Hello 1 #include<stdio.h> 2 #

PAT 1006 换个格式输出 C语言

让我们用字母B来表示"百".字母S表示"十",用"12...n"来表示个位数字n(<10),换个格式来输出任一个不超过3位的正整数.例如234应该被输出为BBSSS1234,因为它有2个"百".3个"十".以及个位的4. 输入格式:每个测试输入包含1个测试用例,给出正整数n(<1000). 输出格式:每个测试用例的输出占一行,用规定的格式输出n. 输入样例1: 234 输出样例1: BBSSS1