Construct a script engine using C language (4)
Author: kevin_qing
Please note
As in the previous chapter, the syntax analysis section does not prepare to directly generate code using YACC, but only uses the analysis table generated by YACC.
BNF:
% Token ID if else switch goto return number string main
% Token add_op mul_op assign_op cmp_op logic_op1 logic_op2
% Token lparen rparen lbrace rbrace colon comma semi
%
Prog
: Main lparen rparen cpd_smt
;
Cpd_smt
: Lbrace smt_seq rbrace
;
Smt_seq
: Lb_smt
| Smt_seq lb_smt
;
Lable: Id colon
;
Lb_smt
: SMT
| Lable SMT
;
SMT
: Expr semi
| Semi
| Goto ID semi
| Return semi
| If lparen expr rparen SMT
| If lparen expr rparen SMT else SMT
| Switch lparen expr rparen lbrace cases rbrace
| Cpd_smt
;
Case: Numbers colon SMT
;
Cases: Case
| Cases case
;
Numbers: add_op number
| Number
;
Strings: String
| Strings string
;
Pam_list
: Expr
| Pam_list comma expr
;
Pri_expr
: ID
| Numbers
| Strings
| Lparen expr rparen
;
Post_expr
: Pri_expr
| ID lparen rparen
| ID lparen pam_list rparen
;
Mul_expr
: Post_expr
| Mul_expr mul_op post_expr
;
Add_expr
: Mul_expr
| Add_expr add_op mul_expr
;
Cmp_expr
: Add_expr
| Add_expr cmp_op add_expr
;
Logic_expr
: Cmp_expr
| Logic_expr logic_op2 cmp_expr
| Logic_op1 cmp_expr
;
Expr
: Logic_expr
| ID assign_op expr
;
%
Use bison ++-o-v bnf.txt to compile and generate O. Output and other files.
I only use the output of O. output.
Part of O. Output
State 69 contains 1 shift/reduce conflict. // There is a conflict about the hanging else. Here, the default state transfer of YACC is correct and no other processing is required.
Grammar
Syntax Rules, // I generate a statute function through this recognition.
---------------
Rule 1 prog-> main lparen rparen cpd_smt
Rule 2 cpd_smt-> lbrace smt_seq rbrace
Rule 3 smt_seq-> lb_smt
--------------
State transfer, the program builds an analysis table by identifying the State transfer line.
The left side is the identifier of the input, and the right side is the action.
------------------------
State 0
Main shift, and go to state 1
Prog go to state 80
-------------------------
There may be four types of actions
Shift, and go to State [N]
Reduce using rule [N]...
Go to State [N]
Accept
Create an analysis table using the status transition table.
Here I wrote a small program to implement automatic generation of analysis tables and statute functions.
Lpcstr lablename [] = {"ID", "if", "else", "Switch", "Goto", "Return", "Number", "string ", "Main ",
"Add_op", "mul_op", "assign_op", "cmp_op", "logic_op1", "logic_op2 ",
"Lparen", "rparen", "lbrace", "rbrace", "colon", "comma", "semi ",
"Prog", "cpd_smt", "smt_seq", "lable", "lb_smt", "SMT", "case", "cases ",
"Numbers", "strings", "pam_list", "pri_expr", "post_expr", "mul_expr", "add_expr", "cmp_expr", "logic_expr", "expr ", "$ end"
};
# Define CNT (sizeof (lablename)/sizeof (lablename [0])
Char * gettoken (char * & P ){
While (* P ){
If (* P = '') | (* P = '/t ')){
++ P;
} Else {
Char * r = P;
While (* P ){
If ('/N' = * P) | ('/t' = * P) | (''= * p )){
* P = 0;
++ P;
Break;
} Else {
++ P;
}
}
Return R;
}
};
Return NULL;
}
Bool Sm (lpcstr S, lpcstr d ){
If (S & D ){
Return 0 = strcmp (S, d );
}
Return false;
}
# Define M (x) (Sm (gettoken (P), x ))
Void yy2ini (){
File * fp = fopen ("lalranalysis table .txt", "R ");
File * FPO = fopen ("lalr. ini", "W ");
File * FP1 = fopen ("rfun. c", "W ");
Char TMP [4096];
While (fgets (TMP, 4096, FP )){
Char * P = TMP;
Char * r = gettoken (P );
Int I;
If (Sm (R, "State ")){
R = gettoken (P );
If (r)
{
I = atoi (R );
Fprintf (FPO, "[S % d]/n", I );
}
} Else if (Sm (R, "rule ")){
Char * R1 = gettoken (P );
If (R1 ){
Int n = atoi (R1 );
Char * TMP [1024];
Int I = 0;
R = gettoken (P );
If (r) if (M ("-> ")){
While (TMP [I] = gettoken (p) ++ I;
Fprintf (FP1, "// rule [% d] % s->", N, R );
For (Int J = 0; j <I; ++ J)
Fprintf (FP1, "% s", TMP [J]);
Fprintf (FP1,
"/Nvoid reduce % d () {/N", N );
For (Int J = 0; j <I; ++ J)
Fprintf (FP1,
"Assert (tokenstack [% d]-> tokentype = % s);/N",-J-1, TMP [i-j-1]);
If (I> 1)
Fprintf (FP1,
"Tokenstack. Pop (% d);/N", I-1 );
Fprintf (FP1,
"Tokenstack [-1]-> tokentype = % s;/N"
"Statestack. Pop (% d);/N"
"}/N", R, I );
}
}
} Else {
Char * R1 = gettoken (P );
If (Sm (R1, "shift ,"))
{
If (M ("and") & M ("go") & M ("to") & M ("state ")){
R1 = gettoken (P );
If (R1 ){
I = atoi (R1 );
Fprintf (FPO, "% s = S % d/N", R, I );
}
}
} Else if (Sm (R1, "go ")){
If (M ("to") & M ("state ")){
R1 = gettoken (P );
If (R1 ){
I = atoi (R1 );
Fprintf (FPO, "% s = g % d/N", R, I );
}
}
} Else if (Sm (R1, "reduce") // reduce using rule
{
If (M ("using") & M ("rule ")){
R1 = gettoken (P );
If (R1 ){
I = atoi (R1 );
Fprintf (FPO, "% s = R % d/N", R, I );
}
}
}
}
}
Fclose (FP );
Fclose (FPO );
Fprintf (FP1, "typedef void reduce ();/N"
"Reduce * reduce [] = {/N ");
For (INT I = 1; I <44; ++ I)
Fprintf (FP1, "/T & reduce % d,/N", I );
Fprintf (FP1, "};/N ");
Fclose (FP1 );
}
Main Program (lalr Analysis)
Void main (){
Sccompiler SC;
SC. INIT ();
SC. Open ("test. SC ");
Statestack. Push (0 );
Tokenstack. Push (new token (START, 0 ));
While (1)
Try {
Token * P = SC. gettoken ();
// Printf ("Get % s @ % d/N", lablename [p-> tokentype], p-> line );
Rescan:
If (statestack [st_top] = 80) & P-> tokentype = endofstream)
Break;
Uint32_t r = lalrtab [statestack [st_top] [p-> tokentype & 0 xFFFF];
Switch (R & 0xf0000 ){
Case smask:
Tokenstack. Push (P );
Statestack. Push (R & 0 xFFFF );
Break;
Case rmask :{
Uint32_t id = R;
Do {
ID & = 0 xFFFF;
Reduce [ID-1] ();
Id = lalrtab [statestack [st_top] [tokenstack [st_top]-> tokentype & 0 xFFFF];
} While (ISR (ID ));
If (ISG (ID )){
Statestack. Push (ID & 0 xFFFF );
// Statestack [0] = (ID & 0 xFFFF );
Goto rescan;
} Else
Assert (false );
}
Default:
Assert (false );
}
} Catch (int err) {printf ("EOF % d", err); break ;}
Printf ("Accept/N ");
Printf ("statestack % d/N", statestack [st_top]);