# Flex&Bison入门
## **第1关 [Flex首次尝试](https://www.educoder.net/tasks/okcfst8uazbl)**
```lex
int num_lines=0,num_chars=0;
%%
\n ++num_lines;
. ++num_chars;
%%
int main()
{
yylex();
printf("Lines=%d,Chars=%d\n",num_lines,num_chars);
}
```
## **第2关 [简单Pascal-like toy语言识别补全](https://www.educoder.net/tasks/tb69ixypmvjq)**
```lex
%{
#include <math.h>
%}
DIGIT [0-9]
ID [a-z][a-z0-9]*
%%
{DIGIT}+ {printf( "An integer: %s (%d)\n", yytext,atoi( yytext ) );}
{DIGIT}+"."{DIGIT}* {printf( "A float: %s (%g)\n", yytext,atof( yytext ) );}
if|then|begin|end|procedure|function {printf( "A keyword: %s\n", yytext );}
{ID} printf( "An identifier: %s\n", yytext );
"+"|"-"|"*"|"/" printf( "An operator: %s\n", yytext );
"{"[^}\n]*"}"
[ \t\n]+
. printf( "Unrecognized character: %s\n", yytext );
%%
int main( argc, argv )
int argc;
char **argv;
{
++argv, --argc; /* skip over program name */
if ( argc > 0 )
yyin = fopen( argv[0], "r" );
else
yyin = stdin;
yylex();
}
```
## **第3关 [Flex规则匹配顺序](https://www.educoder.net/tasks/n6mktgir5w2u)**
![image-20211027132058746](过程.assets/image-20211027132058746.png)
```
132311132
```
## **第4关 [Flex词法规则补全(PL语言)](https://www.educoder.net/tasks/5zc2x6qoprbg)**
![预览大图](过程.assets/2135883.jpeg)
![image-20211027134358631](过程.assets/image-20211027134358631.png)
样例出现了表格中没有出现的字符 再自己定义一个`ERROR` 来包含这些字符。
![image-20211027134502328](过程.assets/image-20211027134502328.png)
```lex
/* PL词法分析器 */
/* 功能:能够识别出PL支持的所有单词符号并给出种别值 */
/* 说明:在下面的begin和end之间添加代码,已经实现了标识符和整常量的识别,你需要完成剩下的部分,加油吧! */
/* 提示:因为是顺序匹配,即从上至下依次匹配规则,所以需要合理安排顺序~ */
%{
#include <stdio.h>
%} /*** begin ****/
OFSYM of
ARRAYSYM array
MODSYM mod
ANDSYM and
ORSYM or
NOTSYM not
PROGRAMSYM program
BEGINSYM begin
ENDSYM end
IFSYM if
THENSYM then
ELSESYM else
WHILESYM while
DOSYM do
CALLSYM call
CONSTSYM const
TYPESYM type
VARSYM var
PROCSYM procedure
ERROR [~!@#$%^&_]?|\\
INTCON [\-]?[1-9][0-9]*|0
IDENT [A-Za-z][A-Za-z0-9]*
CHARCON ['][^']*[']
PLUS \+
MINUS \-
TIMES \*
DIVSYM \/
BECOME :=
EQL \=
NEQ <>
LEQ <=
LSS \<
GEQ >=
GTR \>
LBRACK \[
RBRACK \]
LPAREN \(
RPAREN \)
COMMA \,
SEMICOLON \;
PERIOD \.
COLON \:
%%
{OFSYM} {printf("%s: OFSYM\n", yytext);}
{ARRAYSYM} {printf("%s: ARRAYSYM\n", yytext);}
{PROGRAMSYM} {printf("%s: PROGRAMSYM\n", yytext);}
{MODSYM} {printf("%s: MODSYM\n", yytext);}
{ANDSYM} {printf("%s: ANDSYM\n", yytext);}
{ORSYM} {printf("%s: ORSYM\n", yytext);}
{NOTSYM} {printf("%s: NOTSYM\n", yytext);}
{BEGINSYM} {printf("%s: BEGINSYM\n", yytext);}
{ENDSYM} {printf("%s: ENDSYM\n", yytext);}
{IFSYM} {printf("%s: IFSYM\n", yytext);}
{THENSYM} {printf("%s: THENSYM\n", yytext);}
{ELSESYM} {printf("%s: ELSESYM\n", yytext);}
{WHILESYM} {printf("%s: WHILESYM\n", yytext);}
{DOSYM} {printf("%s: DOSYM\n", yytext);}
{CALLSYM} {printf("%s: CALLSYM\n", yytext);}
{CONSTSYM} {printf("%s: CONSTSYM\n", yytext);}
{TYPESYM} {printf("%s: TYPESYM\n", yytext);}
{VARSYM} {printf("%s: VARSYM\n", yytext);}
{PROCSYM} {printf("%s: PROCSYM\n", yytext);}
{INTCON} {printf("%s: INTCON\n", yytext);}
{IDENT} {printf("%s: IDENT\n", yytext);}
{CHARCON} {printf("%s: CHARCON\n", yytext);}
{PLUS} {printf("%s: PLUS\n", yytext);}
{MINUS} {printf("%s: MINUS\n", yytext);}
{TIMES} {printf("%s: TIMES\n", yytext);}
{DIVSYM} {printf("%s: DIVSYM\n", yytext);}
{BECOME} {printf("%s: BECOME\n", yytext);}
{EQL} {printf("%s: EQL\n", yytext);}
{NEQ} {printf("%s: NEQ\n", yytext);}
{LEQ} {printf("%s: LEQ\n", yytext);}
{LSS} {printf("%s: LSS\n", yytext);}
{GEQ} {printf("%s: GEQ\n", yytext);}
{GTR} {printf("%s: GTR\n", yytext);}
{LBRACK} {printf("%s: LBRACK\n", yytext);}
{RBRACK} {printf("%s: RBRACK\n", yytext);}
{LPAREN} {printf("%s: LPAREN\n", yytext);}
{RPAREN} {printf("%s: RPAREN\n", yytext);}
{COMMA} {printf("%s: COMMA\n", yytext);}
{SEMICOLON} {printf("%s: SEMICOLON\n", yytext);}
{PERIOD} {printf("%s: PERIOD\n", yytext);}
{COLON} {printf("%s: COLON\n", yytext);}
{ERROR} {printf("%s: ERROR\n", yytext);}
\n {}
. {}
%% /*** end ***/
int yywrap() { return 1; }
int main(int argc, char **argv)
{
if (argc > 1) {
if (!(yyin = fopen(argv[1], "r"))) {
perror(argv[1]);
return 1;
}
}
while (yylex());
return 0;
}
```
## **第5关 [Bison入门(逆波兰式计算)](https://www.educoder.net/tasks/tx8w5u2pqlhs)**
本关任务是**利用YACC/Bison构建一个逆波兰符号计算器**。
```bison
%{
#include <ctype.h>
#include <stdio.h>
#include <math.h>
int yylex (void);
void yyerror (char const *);
%}
%define api.value.type {double}
%token NUM
%%
/* Grammar rules and actions follow. */
input:
%empty
| input line
;
line:
'\n'
| exp '\n' { printf ("%.10g\n", $1); }
;
exp:
NUM { $$ = $1; }
/* begin */
| exp exp '+' { $$ = $1 + $2; }
| exp exp '-' { $$ = $1 - $2; }
| exp exp '*' { $$ = $1 * $2; }
| exp exp '/' { $$ = $1 / $2; }
/* Exponentiation */
| exp exp '^' { $$ = pow ($1, $2); }
/* Unary minus */
| exp 'n' { $$ = -$1; }
/* end */
;
%%
/* The lexical analyzer returns a double floating point
number on the stack and the token NUM, or the numeric code
of the character read if not a number. It skips all blanks
and tabs, and returns 0 for end-of-input. */
int yylex (void)
{
int c;
/* Skip white space. */
while ((c = getchar ()) == ' ' || c == '\t')
continue;
/* Process numbers. */
if (c == '.' || isdigit (c))
{
ungetc (c, stdin);
scanf ("%lf", &yylval);
return NUM;
}
/* Return end-of-input. */
if (c == EOF)
return 0;
if (c == '!')
return 0;
/* Return a single char. */
return c;
}
int main (int argc, char** argv)
{
yyparse();
return 0;
}
/* Called by yyparse on error. */
void yyerror (char const *s)
{
fprintf (stderr, "%s\n", s);
}
```
只需编写该部分:
![image-20211027135345729](过程.assets/image-20211027135345729.png)
## **第6关 [bison入门(中缀式计算)](https://www.educoder.net/tasks/tejxvr2lish7)**
继续使用`Bison`,完成中缀式计算器的语法规则设计
```lex
%{
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int yylex(void);
void yyerror(char const *);
%}
%define api.value.type {double}
/* Tokens */
%token NUM
%token EOL
%token ADD SUB MUL DIV
/* begin */
/* end */
%%
/* Grammar rules and actions follow. */
/* begin */
calclist:
%empty
|calclist exp EOL {printf("=%.10g\n",$2);}
exp: factor { $$ = $1; }
| exp ADD factor { $$ = $1 + $3; }
| exp SUB factor { $$ = $1 - $3; }
;
factor: term { $$ = $1; }
| factor MUL term { $$ = $1 * $3; }
| factor DIV term { $$ = $1 / $3; }
;
term:NUM
;
/* end */
%%
/* The lexical analyzer returns a double floating point
number on the stack and the token NUM, or the numeric code
of the character read if not a number. It skips all blanks
and tabs, and returns 0 for end-of-input. */
/* begin */
int yylex(void)
{
int c;
while((c=getchar())==' '||c=='\t')
continue;
if(c=='.'||isdigit(c))
{
ungetc(c,stdin);
if(scanf("%lf",&yylval)!=1)
abort();
return NUM;
}
switch(c){
case EOF: return YYEOF;
case '\n':return EOL;
case '+': return ADD;
case '-': return SUB;
case '*': return MUL;