小白说编译原理lex和yacc环境配置-多图

lex和yacc的使用很简单,但环境配置却是各种问题,本章说明lex和yacc在windows下的环境配置。

软件需求:
系统 win7-64位(win7-32, win8, win10全部通过)
c++编译器: vs2010(2008,2013,2015也全部通过)
lex和yacc编译器: ParGen.exe

基本流程:
安装Pargen.exe,采用的默认目录安装在C:Program Files (x86)Parser Generator 2
安装vs2010,这个各种教程,不再赘述

启动Pargen程序,并选择Project->ParserWizard…
这里写图片描述

选中ParserWizard,开始工程的创建,此处我创建功能,命名为Test,目录位置可自己选择,目标语言为C++,编译器为vc++(32-bit)
这里写图片描述

下一步,选择是创建lex,还是yacc,还是两者兼有。此处我选择是lex和yacc都有,准备实现一个不支持变量的计算器,使用lex识别token,使用yacc识别语法。
这里写图片描述

下一步,设置yacc的文件名字以及使用的解析器,此处我使用的默认选项,不进行修改,文件名默认为myparser.y
这里写图片描述

下一步,设置lex的文件名以及使用的分析器的名字,此处我使用的默认选项,文件名默认为mylexer.l
这里写图片描述

点击完成按钮,创建工程完毕,同时有两个文件mylexer.l 和myparser.y
这里写图片描述

工程的管理,可使用window->project菜单,查看工程下的所有文件
这里写图片描述
这里写图片描述

当你点击文件编辑窗口的放大按钮,会将其他的文件编辑覆盖,此时可以使用window->project菜单查看,也可以使用window->Tile vertically查看全部文件的平铺
这里写图片描述

编辑mylexer.l文件,粘贴入以下内容:

%{
//this code will be added into the header of generated .cpp file
#include <iostream>
#include "myparser.h"
using namespace std;

//already defined in yacc.y, use %token...
//enum{LT,  EQ, GT, IF, ELSE, ID, NUMBER, PLUS, MINUS, TIMES, OVER, INT, DOUBLE,CHAR, LP,RP};

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 mylexer

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


%%
%{
//this code will be added into yyaction function
    YYSTYPE YYFAR& yylval = *(YYSTYPE YYFAR*)yyparserptr->yylvalptr;
    //double yylval;
%}

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

"+"         {print_token(PLUS, yytext); return PLUS;}
"-"         {print_token(MINUS, yytext); return MINUS;}
"*"         {print_token(TIMES, yytext); return TIMES;}
"/"         {print_token(OVER, yytext); return OVER;}
"("         {return LP;}
")"         {return RP;}
"
"        {return EOL;}
{id}        { return ID;}
{number}    { yylval = atof(yytext);return NUMBER;}
"//".*      {return COMMENT;}
"."          {printf("Mystery character %s
", yytext); }
%%



static void print_token(int token, char* lex)
{
#ifdef LEX_DEUB
    cout<<"token:" << token<<" "<<"lex:"<<lex<<endl;
#endif
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

编译myparser.y文件,粘贴入以下内容

%{
#include "mylexer.h"
%}



%name myparser
// class definition
{
    // place any extra class members here
}
// constructor
{
    // place any extra initialisation code here
}

// destructor
{
    // place any extra cleanup code here
}

// place any declarations here
%include {
#ifndef YYSTYPE
#define YYSTYPE double
#endif
}

%token NUMBER ID
%token PLUS MINUS TIMES OVER
%token LP RP EOL COMMENT
%TOKEN INT DOUBLE CHAR

%left PLUS MINUS
%left TIMES OVER
%right UMINUS

%%

lines   :   lines expr EOL  { printf("%g
", $2); }
        |   lines EOL
        |  lines COMMENT
        |
        ;

expr    :   expr PLUS expr  { $$ = $1 + $3; }
		|	expr MINUS expr	{ $$ = $1 - $3; }
		|	expr TIMES expr	{ $$ = $1 * $3; }
		|	expr OVER expr	{ $$ = $1 / $3; }
		|	LP expr RP	{ $$ = $2; }
		|	'-' expr %prec UMINUS	{ $$ = -$2; }
		|	NUMBER {$$=$1;} //$$=$1 can be ignored
        |   ID //should be complemented
        ;  
%%



int main(int argc, char *argv[])
{
    printf("a cacluator which support +,-,*,/ and (): 
");
    printf("    e.g.  12.2+3*(2+5)
");
    int n = 1;
    mylexer lexer;
    myparser parser;
    if (parser.yycreate(&lexer)) {
        if (lexer.yycreate(&parser)) {
            //lexer.yyin = new ifstream(argv[1]);
            //lexer.yyout = new ofstream(argv[2]);
            n = parser.yyparse();
            //parse_tree.get_label();
            //parse_tree.gen_code(*lexer.yyout);
        }
    }

    getchar();
    return n;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79

点击Pargen右上角的编译build按钮,会生成相应的.h和.cpp代码
这里写图片描述
这里写图片描述

新建vs2010工程,并将生成的.h和.cpp代码加入到工程中。简单起见,在compleTest目录下创建vs工程vsTest
这里写图片描述

选择控制台工程, 工程的目录,以及工程名称vsTest,点击确定按钮后
这里写图片描述

继续下一步配置
这里写图片描述

此处附件选项选择空项目,然后点击完成按钮,即完成vsTest工程创建
这里写图片描述

工程右键添加现有项,即添加已经生成.h和.cpp文件
这里写图片描述
这里写图片描述
这里写图片描述

在vs界面,点击编译按钮,查看当前的编译情况,会显示编译错误,找不到yy的头文件,这是因为并没有将Pargen安装后的头文件加入到工程的包含目录中
这里写图片描述

下面将Pargen安装后的头文件加入到工程include配置
这里写图片描述
这里写图片描述
这里写图片描述

在vs界面,点击编译按钮,查看编译情况。 当前头文件可以正常找到,会出现大量的链接错误-link error。这是因为对应的lib文件还没有加载进来。
这里写图片描述

下面加入库文件,加入库所在目录
这里写图片描述

加入要使用的库的名字:ylmtri.lib, 注意使用分号隔开
这里写图片描述

再次点击编译按钮,会发现可以编译,但是运行的时候,会出现ylmtri.dll的错误。这是因为我们使用动态dll库,需要将对应的dll文件从Pargen目录复制到工程目录的exe文件同级目录下
这里写图片描述

下面开始将ylmtri.dll从Pargen目录复制到vsTest.exe同级目录
这里写图片描述
这里写图片描述

再次点击编译运行按钮,可以正常运行,效果如下
这里写图片描述
这里写图片描述

终于完结了。

原文地址:https://www.cnblogs.com/1996313xjf/p/6075582.html