Parser Generator使用说明

Parser Generator的使用说明

最近1个星期,大致学习了一下lex,虽然在windows系统上它并没有我所期望的强大,在调试和编写代码都遇到了不少困难,但是总体来说Parser Generator还是让我体会到了lex编程的快捷, 为了自己加深印象把一些参考资料和认识总结了一下.

1.     parser generator是什么?

它是一款在windows下编写lex/yacc程序的工具.可以到

http://www.bumblebeesoftware.com/downloads.htm

下载

2.     parser generator的使用方法

这里只以vc6.0为例,首先打开parser generator编辑器,选择Project->LibBuilder

LibBuilder对话框中选中Visual C++(32-bit),按属性键Properties后确以下设置

Script file name                        ./Cpp/Script/msvc32.lbs

Name                                    Visual C++(32-bit)

Directory                               msvc32

Compiler Version                         Version 6

Unicode                                  True

Treat wchar_t as Built-in Type            False

Compiler Bin Directory             安装路径/Microsoft Visual Studio/Vc98/bin

Compiler Bin Directory(2) 安装路径/Microsoft Visual Studio/Common/MSDev98/bin

Compiler Include Directory      安装路径/Microsoft Visual Studio/Vc98/include

Compiler Include Directory(2)               

Compiler Library Directory          安装路径/Microsoft Visual Studio/Vc98/lib

Compiler Library Directory(2)               

Libraries下的库文件全部选中后ok

LibBuilder对话框->Build(编译过程可能几分钟)

编译完成后我们就可以使用parser generator编写lex或是yacc程序了

Project->ParserWizard

Step1 工程设定(一点需要注意语言可以选择c或是c++java)

Step2 工程设定(默认创建带main函数的yacc文件和lex文件)

Step3 yacc文件设定

Step4 lex文件设定

 

Lexyacc的语法参考http://www.ibm.com/developerworks/cn/linux/sdk/lex/

编辑好代码后Project->RebBuild All在你创建好的工程下自动生成Step1选定语言的文件(.h/..c/.cpp/.java)

之后在vc6.0加入如下设置

Tool->Option-> directory

Bin file :

安装目录/PARSER GENERATOR 2/BIN

Include file:

安装目录/PARSER GENERATOR 2/CPP/INCLUDE

Library file

安装目录/PARSER GENERATOR 2/CPP/LIB/MSVC32

Soure file

安装目录/PARSER GENERATOR 2/CPP/SOURCE

创建vc6.0工程

将生成文件复制到vc6.0创建工程下

Source filesHeader Files中加入生成文件(.h/.c/.cpp)

在工程设定中Project->Settings For box选中win32 debug

c/c++ ->Category选中General ->Preprocessor Definitions加入YYDEBUG

在工程Project设定Project->Settings For box中选中all

link -> Category选中General->Object/Library Modules中加入yld.lib

这里需要注意的是yld.libparser generatorDUBUG单线程版本,对于vc的控制台程序是可以的,如果使用了MFC或是Windows applications程序则需要对应下表追加

Library(DEBUG)

Run-time Library

Description

yld.lib

Debug Single-Threaded

单线程静态链接库(DEBUG版本)

ylmtd.lib

Debug Multithreaded

多线程静态链接库(DEBUG版本)

ylmtrd.lib

Debug Multithreaded DLL

多线程静态链接库当run time library 使用动态库(DEBUG版本)

ylmtrid.lib    

Debug Multithreaded DLL

多线程动态链接库当run time library 使用动态库(DEBUG版本)

 

Library(RELEASE)

Run-time Library

Description

yl.lib

Single-Threaded

单线程静态链接库(RELEASE版本)

ylmt.lib

Multithreaded

多线程静态链接库(RELEASE版本)

ylmtr.lib

Multithreaded DLL      

多线程静态链接库当run time library 使用动态库(RELEASE版本)

ylmtri.lib

Multithreaded DLL      

多线程动态链接库当run time library 使用动态库(RELEASE版本)

如果使用了动态库版本需要在程序运行环境中追加DLL的地址

安装目录/PARSER GENERATOR 2/CPP/LIB/MSVC32

如果需要链接yacc或是lexdll.Preprocessor Definitions下加入YYDLL.

 

这样就可以使用vc6.0lex生成文件进行编译了

3PG2的默认输FILE *,怎样转char *?
PG2
提供了两方法,一是重定yyinput,二是重定yygetchar实际使用中后者方便,因yyinput除了yygetchar之外需要负责lineno量的增加。
yygetchar通常这样
int yygetchar(void)
{
     if (* inputstring=='/0')
     {
           return -1;
     }
     return (unsigned char) * inputstring++;
}
唯一要注意的就是char *的末尾要返回一个-1代表EOF,使得yyinput停止。(感luocong的提醒)。

4
、同理,yyoutput
FILE *char *
直接
yytext操作既可,yytext就是char[]

3,4说明转自

http://blog.csdn.net/tankaiha/archive/2005/12/13/551457.aspx

总体来说lex/yacc比起自己编写分析程序要快的多,但是不足点就是错误的调试会非常困难,需要把.lex/.l.yacc/.y文件加入工程调试,每次变更都需要重新编译parser generator工程,然后再次粘贴,lex的语法熟练度可能决定了效率,新手基于模型为基础进行研究逐步认识parser generator是最佳的学习方法,

Lex的自带例程在/Parser Generator 2/Cpp/Examples ,在这对其中的class(四则计算器)做下简单说明

lexer.l文件

%{              //%{ %}中的c代码将被复制到.cpp文件中

#include

#include

#include

#include "parser.h"//自动生成头文件必须包含

%}

 

// include file

%include {              //%include {}里的代码复制到对应的.h文件中,这里声明calc_parser

class calc_parser;   // symboltable是为在下面calc_lexer::create函数能够找到使用类型的提前

class symboltable;  //声明

}

 

// lexical analyser name

%name calc_lexer         //%name指定继承自lexer的类名{}中为类成员声明,类的声明将被解//释到.h文件中

// class definition

{

// Attributes

protected:

        symboltable* m_symboltable;             // the symbol table

 

// Operations

public:

        int create(calc_parser* parser, symboltable* symboltable);

       

        // attribute commands

        double number() const;

        symbol* id() const;

}

 

// constructor

{

        // do nothing

}

 

// macros

exponent        ([Ee][+-]?[0-9]+)  //科学计算方定义为exponent

 

%%

 

%{

// extract yylval for use later on in actions

YYSTYPE& yylval = *(YYSTYPE*)yyparserptr->yylvalptr;//指定yylval值的类型

%}

 

// 对于数字的规则处理 |表示或,|下一个算式使用的规则与第一个相同{}中是规则执行代码

[0-9]+"."[0-9]*{exponent}?      |

"."[0-9]+{exponent}?            |

[0-9]+{exponent}?                       { yylval.value = number(); return NUMBER; }

 

//对于3角函数的规则处理

"sin"                                           { return SIN; }

"cos"                                           { return COS; }

"tan"                                           { return TAN; }

 

// 对于变量的规则处理

[a-zA-Z_][a-zA-Z0-9_]*          { yylval.symbol = id(); return ID; }

 

//对于符号的规则处理

"="                                                     { return '='; }

"+"                                                     { return '+'; }

"-"                                                     { return '-'; }

"*"                                                     { return '*'; }

"/"                                                     { return '/'; }

"("                                                     { return '('; }

")"                                                     { return ')'; }

 

// 对于特殊符号的处理

[ /t]                                           { /* do nothing */ }

/n                                                      { return '/n'; }

 

.                                                       { printf("invalid character '0x%02x'/n", (unsigned int)yytext[0]); }

 

%%

 

/

// 以下都是对成员函数的实现,将被复制到.cpp文件中

 

int calc_lexer::create(calc_parser* parser, symboltable* symboltable)

{

        assert(parser != NULL);

        assert(symboltable != NULL);

       

        m_symboltable = symboltable;

        return yycreate(parser);

}

 

/

// calc_lexer attribute commands

 

double calc_lexer::number() const

{

        errno = 0;              // clear error flag

        char* endp;

        double d = strtod(yytext, &endp);

        if ((d == +HUGE_VAL || d == -HUGE_VAL) && errno == ERANGE) {

                printf("number too big/n");

        }

        return d;

}

 

symbol* calc_lexer::id() const

{

        symbol* p = m_symboltable->install(yytext);

        return p;

}//lexer.l end

 

parser.y文件

%{                      //%{ %}中的c代码将被复制到.cpp文件中

#include

%}

 

// include file

%include {              //%include {}里的代码复制到对应的.h文件中,这里声明symbol

 // 是为在下面calc_parser:: assign函数能够找到使用类型的提前

 //声明

// forward references

class symbol;

}

 

//%union表示使用联合体声明yytest的类型可能有2,也就是lex返回的标记的值的类型(//一个标记都会有一个值)

%union {

        symbol* symbol;

        double value;

}

 

// nonterminals

%type expr  //%type是声明变量exprdouble类型,这里要注意的是<>声明的类型必//须是在%union中定义的变量

//这里要注意下越是后声明的越高

%right '='          //%right声明=为右结合

%left '+', '-'  //%left 声明+ -为左结合

%left '*', '/'        //%left 声明* /为左结合

%right UMINUS     //%right声明UMINUS为右结合,此优先级最高

 

%token NUMBER //%token声明标记NUMBER和其类型,%type注意点一样

%token ID     //声明标记ID的类型,%type注意点一样

 

// keywords

%token SIN           //声明标记SIN,因为本身的值没有用途所以不对其类型特殊声明

%token COS           //声明标记COS,因为本身的值没有用途所以不对其类型特殊声明

%token TAN           //声明标记TAN,因为本身的值没有用途所以不对其类型特殊声明

 

// include file

%include {

#include "symbol.h"  //%{ %}中的c代码将被复制到.h文件中

#include "lexer.h"

}

 

// parser name

%name calc_parser   //%name指定继承自lexer的类名{}中为类成员声明,类的声明将被解

//释到.h文件中

// class definition

{

// 类成员声明

protected:

        symboltable m_symboltable;              // the symbol table

        calc_lexer m_lexer;                             // the lexical analyser

       

// Operations

public:

        int create();

       

        // attribute commands

        double assign(symbol* id, double value);

        double divide(double dividend, double divisor);

}

 

// constructor

{

        // do nothing

}

 

%%

lines

        : lines line

        | /* empty */

        ;

 

line

        : expr '/n'                                     { printf("%g/n", (double)$1); }

        | error '/n'                            { yyerrok(); }

        ;

//这里只对expr进行说明$$是冒号左边表达式的值   $1为右边第一个表达式的值

$2为右边第二个表达式的值  $3为右边第三个表达式的值,以此类推.

expr

        : ID '=' expr                           { $$ = assign($1, $3); }//变量保存

        | expr '+' expr                         { $$ = $1 + $3; }

        | expr '-' expr                         { $$ = $1 - $3; }

        | expr '*' expr                         { $$ = $1 * $3; }

        | expr '/' expr                         { $$ = divide($1, $3); }//除法判断

        | '(' expr ')'                          { $$ = $2; }

        | '-' expr %prec UMINUS         { $$ = -$2; }

// %prec说明'-' expr表达式的优先级和UMINUS一样.

        | NUMBER                                        { $$ = $1; }

        | ID                                            { $$ = $1->m_value; }

        | SIN '(' expr ')'                      { $$ = sin($3); }

        | COS '(' expr ')'                      { $$ = cos($3); }

        | TAN '(' expr ')'                      { $$ = tan($3); }

        ;

 

%%

 

/

//以下都是对成员函数的实现,将被复制到.cpp文件中

 

 

int main(void)

{

        int n = YYEXIT_FAILURE;

       

        calc_parser parser;

        if (parser.create()) {

                n = parser.yyparse();

        }

        return n;

}

 

/

// calc_parser commands

 

int calc_parser::create()

{

        if (!yycreate(&m_lexer)) {

                return 0;

        }

        if (!m_lexer.create(this, &m_symboltable)) {

                return 0;

        }

        return 1;       // success

}

 

/

// calc_parser attribute commands

 

double calc_parser::assign(symbol* id, double value)

{

        assert(id != NULL);

 

        id->m_value = value;

        return id->m_value;

}

 

double calc_parser::divide(double a, double b)

{

        if (b == 0) {

                printf("division by zero/n");

                yythrowerror();         // causes a syntax error

                return 0;

        }

        else {

                return a / b;

        }

}

更多详细参考可以查看Parser Generator Help帮助文档

以上都是作者的辛苦劳动,转载请注明出处.

你可能感兴趣的:(Parser Generator使用说明)