2021-10-29 Compilation Principle Experiment 2 -- lexical analysis

Keywords: C Back-end

1, Experimental requirements

Based on the previous experiment, write a program to analyze the source code written in c-language and print the syntax tree. The main analysis tool used in the experiment is Bison, which uses C language to complete the program.

  • Basic Requirements
    a. Parsing the program and outputting the parsing results;
    b. Be able to recognize syntax errors in multiple locations.
  • Additional requirements
    a. Output the syntax tree with line number information according to the correct indentation format;
    b. Able to handle simple syntax errors;

2, tree.h

#ifndef TREE_H
#define TREE_H

#include <string.h>

(1) In order to output the syntax analysis tree, we need to identify the type of each node. Therefore, the node type is defined as int, and four node types are specified:

typedef int NODE_TYPE;        // Node Stereotypes 
// Non terminator type
#define NONTERMINAL 0         
// Terminator type
#define INT_ Type 1 / / int type
#define FLOAT_ Type 2 / / float type
#define STRING_TYPE 3 / / printable type

(2) Specify the type of node. Here, the "child brother" node is used:

struct Node {
    struct Node *child;       // Son node
    struct Node *brother;     // Sibling node
    int lineNum;              // Line number
    char *name;               // Node name
    NODE_TYPE type;           // Node Stereotypes 
    union {
        char *id_name;        // ID name
        int intValue;         // int value
        float floatValue;     // float value
    };
};

(3) Define the root node of the syntax tree. Each time a new node is created, the head is its parent:

struct Node *head;              // Root node of parsing tree

(4) Function declaration for syntax tree:

// Function declarations
struct Node *createNode(char *name, int line, NODE_TYPE type);
struct Node *insertNode(struct Node *node, char *name, int line, NODE_TYPE type);
void printNode(struct Node *node, FILE *f);
void printTree(struct Node* head, int depth, FILE *f);
#endif

3, tree.c

#include <malloc.h>
#include <stdio.h>
#include "tree.h"

(1) Create a new node. The node created here is equivalent to the leaf node, which is the node corresponding to the terminator. Therefore, it is mainly used in lizi.l, that is, the corresponding operation when the terminator matches in flex.

/**
 * Create a new node and return
 * @param name Node name
 * @param line Number of rows where the node is located
 * @param type Type of node
 * @return Pointer to new node
 */
struct Node *createNode(char *name, int line, NODE_TYPE type) {
    struct Node *pNode = (struct Node *) malloc(sizeof(struct Node));
    pNode->brother = NULL;         // The brother of the new node is empty
    pNode->child = NULL;           // The child of the new node is empty
    pNode->lineNum = line;         // Record the line number, and then output the useful information
    pNode->type = type;            // Record the node type and output according to the node type
    pNode->name = strdup(name);    // Use the string copy to give the node name of the new node
    pNode->intValue = 1;           // Set the int value to 1 by default
    //printf("%s\n",name);
    return pNode;                  // Return to pNode
}

(2) Insert a new node. Because the idea of the algorithm is bottom-up, the parent node is inserted here. Create a new node, give it an initial value, then set its children to the node given to us, and finally point the head to the parent node, so that each time the new node is created, the head points to the root node of the syntax tree.

/**
 * Insert into parsing tree
 * @param node Bottom node (child node)
 * @param name Name of parent node
 * @param line Number of rows of parent node
 * @param type Type of parent node
 * @return Pointer to parent node
 */
struct Node *insertNode(struct Node *node, char *name, int line, NODE_TYPE type) {
    struct Node *father = (struct Node *) malloc(sizeof(struct Node));
    father->child = node;           // Give the input node a parent
    father->brother = NULL;         // Father's brother is empty
    father->lineNum = line;         // Record the line number, and then output the useful information
    father->type = type;            // Record the node type and output according to the node type
    father->name = strdup(name);    // Use the string copy to give the node name of the new node
    father->intValue = 1;           // Set the int value to 1 by default
    head = father;                  // Set head to father
    //printf("%s %d\n",name,line);
    // if (node)
    //  fprintf(stdout, "%s -> %s   line : %d\n", father -> name, node -> name, line);
    return father;                  // Return to father
}

(3) Printing output according to the type of node is equivalent to printing a line of information in the syntax tree.

/**
 * Print according to the type of node
 * @param node Node pointer
 * @param f output location
 */
void printNode(struct Node *node, FILE *f) {
    if (node->type == STRING_TYPE)
        fprintf(f, "%s : %s\n", node->name, node->id_name);     // string type node output node name and node content
    else if (node->type == INT_TYPE)
        fprintf(f, "INT : %d\n", node->intValue);               // INT type node outputs INT and node value
    else if (node->type == FLOAT_TYPE)
        fprintf(f, "FLOAT : %f\n", node->floatValue);           // The node of FLOAT type outputs FLOAT and node value
    else
        fprintf(f, "%s (%d)\n", node->name, node->lineNum);     // Non terminator output node name and line number
}

(4) The depth first method (DFS) is used to traverse the syntax tree, and the method is function recursion. Here, the fprint function can be used to specify the output file or directly output the console. The output selected here is in the output.txt file, which is convenient for viewing, editing and debugging.

/**
 * Recursive traversal of print syntax tree
 * @param head   Root node of syntax tree
 * @param depth  Depth of syntax tree
 * @param f output location
 */
void printTree(struct Node *head, int depth, FILE *f) {
    if (head == NULL) return;                       // The function ends when an empty node is encountered
    for (int i = 0; i < depth; ++i)
        fprintf(f, "\t");                         // Blank space (TAB) required to print the syntax tree
    printNode(head, f);
    printTree(head->child, depth + 1, f);       // Consider the children of the node, add one to the depth, and enter the next level of recursion
    printTree((head->brother), depth, f);       // Consider the brothers of the node, the depth remains unchanged, and enter the next layer of recursion
}

4, Modification of lizi.l

(1) Errors indicates the number of syntax errors recognized by the compiler, which is convenient to judge whether the program has syntax errors, so as to output the syntax tree.

extern int errors;

/* ... */

. {
    errors++;
    printf("Error type A at Line %d: Mysterious charaters \'%s\'.\n", yylineno, yytext);
}  

(2) Learn from the lessons of the last experiment. Here, set the length of the tab and record the position column information read by the compiler:

// The length of the default tab
#define TABLEN 4

/* ... */

{TAB} { yycolumn += TABLEN; }    /* The default tab length is 4 */

(3) In order to better record the location information read by the compiler, the macro YY is redefined_ USER_ ACTION. Although this experiment was not used, it is believed that future experiments may be used.

// Number of initialization columns
int yycolumn = 1;

// Code executed before each user action is defined
#define YY_USER_ACTION yylloc.first_line = yylloc.last_line = yylineno; \
    yylloc.first_column = yycolumn; \
    yylloc.last_column = yycolumn + yyleng - 1; \
    yycolumn += yyleng;

5, Modification of syntax.y and main function

(1) New and modified parts of syntax.y

%{
    #include <stdio.h>
    #include <stdlib.h>
    #include "tree.h"

    extern int yylineno;
    void yyerror(char*);
    void myerror(char *msg);
    int yylex();
    int errors = 0;                 // Record the number of syntax errors found
    #Define yytype struct Node * / / set all token types to Node*
%}

// Define associativity and prioritization
%right ASSIGNOP
%left OR
%left AND
%nonassoc RELOP
%left PLUS MINUS
%left STAR DIV
%right NAGATE NOT
%right DOT LP LB RP RB
%nonassoc LOWER_THAN_ELSE
%nonassoc ELSE

(2) Change of main function

#include "lex.yy.c"

int main(int argc, char **argv) {
    if (argc <= 1) return 1;
    FILE *f = fopen(argv[1], "r");
    if (!f) {
        perror(argv[1]);
        return 1;
    }
    yylineno = 1;
    yyrestart(f);
    yyparse();

If the syntax error is 0, print the syntax tree to output.txt

    // Output syntax tree
    f = fopen("output.txt", "w");
    if (!f) {   
        perror(argv[1]);
        return 1;
    }
    if (errors == 0) {
        f = fopen("output.txt", "w");
        printTree(head, 0, f);
    }
    return 0;
}

6, Compile code

Input command:

>>> flex lizi.l
>>> bison -d syntax.y
>>> gcc syntax.tab.c -lfl -ly -o parser tree.c

Get the executable program parser, and use the parser to read the file for compilation:

>>> ./parser text.cmm

7, Complete code attached

  1. lizi.l

    %{
        #include "syntax.tab.h"
        #include "tree.h"
    
        extern int errors;
        YYLTYPE yylloc;
    
        // Number of initialization columns
    	int yycolumn = 1;
    
        // The length of the default tab
        #define TABLEN 4
    
        // Code executed before each user action is defined
        #define YY_USER_ACTION yylloc.first_line = yylloc.last_line = yylineno; \
            yylloc.first_column = yycolumn; \
            yylloc.last_column = yycolumn + yyleng - 1; \
            yycolumn += yyleng;
    %}
    
    %option yylineno
    
    digit [0-9]
    letter [a-zA-Z]
    unsignedint [1-9]{digit}*
    
    /* int Type matching */
    INT10 [+-]?(0|{unsignedint})
    INT8 [+-]?0(0|([1-7][0-7]*))
    INT16 [+-]?(0(x|X))(0|([1-9A-Fa-f][0-9A-Fa-f]*))
    INT {INT10}|{INT8}
    
    /* float Type matching */
    FLOAT1 [+-]?({digit}+)?\.{digit}+?
    FLOAT2 [+-]?({digit}+)[eE][+-]?({digit})+
    FLOAT3 [+-]?({digit}+)?\.({digit}+)?([eE][+-]?{digit}+)
    FLOAT {FLOAT1}|{FLOAT2}|{FLOAT3}
    
    /* Matching of other terminators */
    ID ({letter}|_)({letter}|_|{digit})*
    SEMI ;
    COMMA ,
    ASSIGNOP =
    RELOP (>|<|>=|<=|==|!=)
    PLUS \+
    MINUS \-
    STAR \*
    DIV \/
    AND &&
    OR \|\|
    DOT \.
    NOT !
    TYPE (int|float)
    LP \(
    RP \)
    LB \[
    RB \]
    LC \{
    RC \}
    STRUCT struct
    IF if
    ELSE else
    RETURN return
    WHILE while
    LF \n
    OTHER [\r]
    TAB [\t]
    SPACE [ ]
    
    %%
    
     /*-----------------------------------------|
     |                Skip single line comments|
     |-----------------------------------------*/
    "//" {   
        char c;
        while ((c = input()) != '\n');
    }
    
     /*-----------------------------------------|
     |                Skip multiline comments|
     |-----------------------------------------*/
    "/*" {
        char c;
        while ((c = input()) != EOF) {
            if (c == '*') {
                c = input();
                if (c == '/'){
                    break;
                }
            }
        }
        if (c == EOF) printf("Error type B at Line %d: LACK OF */.\n", yylineno);
    }
    
    
     /*-----------------------------------------|
     |          Matching of terminators and corresponding operations|
     |-----------------------------------------*/
    {DOT} { 
        struct Node *pNode = createNode("DOT", 0, STRING_TYPE);
        yylval = pNode;
        pNode->id_name = strdup(yytext);
        return DOT; 
    }
    {TYPE} { 
        struct Node *pNode = createNode("TYPE", 0, STRING_TYPE);
        yylval = pNode;
        pNode->id_name = strdup(yytext);
        return TYPE; 
    }
    {INT} { 
        struct Node *pNode = createNode("INT", 0, INT_TYPE);
        yylval = pNode;
        pNode->intValue = atoi(yytext);
        return INT; 
    }
    {FLOAT} { 
        struct Node *pNode = createNode("FLOAT", 0, FLOAT_TYPE);
        yylval = pNode;
        pNode->floatValue = atof(yytext);
        return FLOAT; 
    }
    {SEMI} { 
        struct Node *pNode = createNode("SEMI", 0, STRING_TYPE);
        yylval = pNode;
        pNode->id_name = strdup(yytext);
        return SEMI; 
    }
    {COMMA} { 
        struct Node *pNode = createNode("COMMA", 0, STRING_TYPE);
        yylval = pNode;
        pNode->id_name = strdup(yytext);
        return COMMA; 
    }
    {ASSIGNOP} { 
        struct Node *pNode = createNode("ASSIGNOP", 0, STRING_TYPE);
        yylval = pNode;
        pNode->id_name = strdup(yytext);
        return ASSIGNOP; 
    }
    {RELOP}  { 
        struct Node *pNode = createNode("RELOP", 0, STRING_TYPE);
        yylval = pNode;
        pNode->id_name = strdup(yytext);
        return RELOP; 
    }
    {PLUS} { 
        struct Node *pNode = createNode("PLUS", 0, STRING_TYPE);
        yylval = pNode;
        pNode->id_name = strdup(yytext);
        return PLUS; 
    }
    {MINUS} { 
        struct Node *pNode = createNode("MINUS", 0, STRING_TYPE);
        yylval = pNode;
        pNode->id_name = strdup(yytext);
        return MINUS; 
    }
    {STAR} { 
        struct Node *pNode = createNode("STAR", 0, STRING_TYPE);
        yylval = pNode;
        pNode->id_name = strdup(yytext);
        return STAR; 
    }
    {DIV} { 
        struct Node *pNode = createNode("DIV", 0, STRING_TYPE);
        yylval = pNode;
        pNode->id_name = strdup(yytext);
        return DIV; 
    }
    {AND} { 
        struct Node *pNode = createNode("AND", 0, STRING_TYPE);
        yylval = pNode;
        pNode->id_name = strdup(yytext);
        return AND; 
    }
    {OR} { 
        struct Node *pNode = createNode("OR", 0, STRING_TYPE);
        yylval = pNode;
        pNode->id_name = strdup(yytext);
        return OR; 
    }
    {NOT} { 
        struct Node *pNode = createNode("NOT", 0, STRING_TYPE);
        yylval = pNode;
        pNode->id_name = strdup(yytext);
        return NOT; 
    }
    {LP} { 
        struct Node *pNode = createNode("LP", 0, STRING_TYPE);
        yylval = pNode;
        pNode->id_name = strdup(yytext);
        return LP; 
    }
    {RP} { 
        struct Node *pNode = createNode("RP", 0, STRING_TYPE);
        yylval = pNode;
        pNode->id_name = strdup(yytext);
        return RP; 
    }
    {LB} { 
        struct Node *pNode = createNode("LB", 0, STRING_TYPE);
        yylval = pNode;
        pNode->id_name = strdup(yytext);
        return LB; 
    }
    {RB} { 
        struct Node *pNode = createNode("RB", 0, STRING_TYPE);
        yylval = pNode;
        pNode->id_name = strdup(yytext);
        return RB; 
    }
    {LC} { 
        struct Node *pNode = createNode("LC", 0, STRING_TYPE);
        yylval = pNode;
        pNode->id_name = strdup(yytext);
        return LC; 
    }
    {RC}  { 
        struct Node *pNode = createNode("RC", 0, STRING_TYPE);
        yylval = pNode;
        pNode->id_name = strdup(yytext);
        return RC; 
    }
    {STRUCT} { 
        struct Node *pNode = createNode("STRUCT", 0, STRING_TYPE);
        yylval = pNode;
        pNode->id_name = strdup(yytext);
        return STRUCT; 
    }
    {RETURN} { 
        struct Node *pNode = createNode("RETURN", 0, STRING_TYPE);
        yylval = pNode;
        pNode->id_name = strdup(yytext);
        return RETURN; 
    }
    {IF} { 
        struct Node *pNode = createNode("IF", 0, STRING_TYPE);
        yylval = pNode;
        pNode->id_name = strdup(yytext);
        return IF; 
    }
    {ELSE} { 
        struct Node *pNode = createNode("ELSE", 0, STRING_TYPE);
        yylval = pNode;
        pNode->id_name = strdup(yytext);
        return ELSE; 
    }
    {WHILE} { 
        struct Node *pNode = createNode("WHILE", 0, STRING_TYPE);
        yylval = pNode;
        pNode->id_name = strdup(yytext);
        return WHILE; 
    }
    
    {ID} { 
        struct Node *pNode = createNode("ID", 0, STRING_TYPE);
        yylval = pNode;
        pNode->id_name = strdup(yytext);
        return ID; 
    }
    {LF} { yycolumn = 1; }           /* Update the number of columns after wrapping */
    {OTHER} { }                      /* No operation is given for other character matches */
    {TAB} { yycolumn += TABLEN; }    /* The default tab length is 4 */
    {SPACE} { yycolumn += 1; }       /* Space encountered, length 1 */
    . {
        errors++;
        printf("Error type A at Line %d: Mysterious charaters \'%s\'.\n", yylineno, yytext);
    }                                /* Other mismatched terminators are reported as errors */
    %% 
    
    
  2. syntax.y

    %{
        #include <stdio.h>
        #include <stdlib.h>
        #include "tree.h"
    
        extern int yylineno;
        void yyerror(char*);
        void myerror(char *msg);
        int yylex();
        int errors = 0;                 // Record the number of syntax errors found
        #Define yytype struct Node * / / set all token types to Node*
    %}
    
    
    %token INT                         /* int type */
    %token FLOAT                       /* float type */
    %token TYPE                        /* TYPE Terminator */
    %token LF                          /* Newline \ n */
    %token ID                          /* identifier  */ 
    %token SEMI COMMA DOT              /* End symbol, */
    %token ASSIGNOP RELOP              /* Comparison assignment symbol = > < > = < = == */
    %token PLUS MINUS STAR DIV         /* Operator + - */ */
    %token AND OR NOT                  /* Judgment symbol & & |! */
    %token LP RP LB RB LC RC           /* Parentheses () [] {} */
    %token STRUCT                      /* struct */
    %token RETURN                      /* return */
    %token IF                          /* if */
    %token ELSE                        /* else */
    %token WHILE                       /* while */
    
    // Define associativity and prioritization
    %right ASSIGNOP
    %left OR
    %left AND
    %nonassoc RELOP
    %left PLUS MINUS
    %left STAR DIV
    %right NAGATE NOT
    %right DOT LP LB RP RB
    %nonassoc LOWER_THAN_ELSE
    %nonassoc ELSE
    
    %%
    
     /*-----------------------------------------|
     |          High-level Definitions          |
     |-----------------------------------------*/
    Program : ExtDefList {
            $$ = insertNode($1, "Program", $1->lineNum, NONTERMINAL);
        }
        ;
    
    ExtDefList : ExtDef ExtDefList {
            $$ = insertNode($1, "ExtDefList", @1.first_line, NONTERMINAL);
            $1->brother = $2;
        }
        | {
            $$ = insertNode(NULL, "ExtDefList", yylineno, NONTERMINAL);
        }
    
        ;
    
    ExtDef : Specifier ExtDecList SEMI {
            $$ = insertNode($1, "ExtDef", @1.first_line, NONTERMINAL);
            $1->brother = $2;
            $2->brother = $3;
        }
        | Specifier SEMI {
            $$ = insertNode($1, "ExtDef", @1.first_line, NONTERMINAL);
            $1->brother = $2;
        }
        | Specifier FunDec CompSt {
            $$ = insertNode($1, "ExtDef", @1.first_line, NONTERMINAL);
            $1->brother = $2;
            $2->brother = $3;
        }
    
    
        ;
    
    ExtDecList : VarDec {
            $$ = insertNode($1, "ExtDecList", @1.first_line, NONTERMINAL);
        }
        | VarDec COMMA ExtDecList {
            $$ = insertNode($1, "ExtDecList", @1.first_line, NONTERMINAL);
            $1->brother = $2;
            $2->brother = $3;
        }
    
    
        ;
    
     /*-----------------------------------------|
     |                Specifiers                |
     |-----------------------------------------*/
    Specifier : TYPE {
            $$ = insertNode($1, "Specifier", @1.first_line, NONTERMINAL);
        }
        | StructSpecifier {
            $$ = insertNode($1, "Specifier", @1.first_line, NONTERMINAL);
        }
        ;
    
    StructSpecifier : STRUCT OptTag LC DefList RC {
            $$ = insertNode($1, "StructSpecifier", @1.first_line, NONTERMINAL);
            $1->brother = $2;
            $2->brother = $3;
            $3->brother = $4;
            $4->brother = $5;
        }
        | STRUCT Tag {
            $$ = insertNode($1, "StructSpecifier", @1.first_line, NONTERMINAL);
            $1->brother = $2;
        }
    
        ;
    
    OptTag : ID {
            $$ = insertNode($1, "OptTag", @1.first_line, NONTERMINAL);
        }
        | {
            $$ = insertNode(NULL, "OptTag", yylineno, NONTERMINAL);
        }
        ;
    
    Tag : ID {
            $$ = insertNode($1, "Tag", @1.first_line, NONTERMINAL);
        }
        ;
    
     /*-----------------------------------------|
     |               Declarators                |
     |-----------------------------------------*/
    VarDec : ID {
            $$ = insertNode($1, "VarDec", @1.first_line, NONTERMINAL);
        }
        | VarDec LB INT RB {
            $$ = insertNode($1, "VarDec", @1.first_line, NONTERMINAL);
            $1->brother = $2;
            $2->brother = $3;
            $3->brother = $4;
        }
        ;
    
    FunDec : ID LP VarList RP {
            $$ = insertNode($1, "FunDec", @1.first_line, NONTERMINAL);
            $1->brother = $2;
            $2->brother = $3;
            $3->brother = $4;
        }
        | ID LP RP {
            $$ = insertNode($1, "FunDec", @1.first_line, NONTERMINAL);
            $1->brother = $2;
            $2->brother = $3;
        }
        ;
    
    VarList : ParamDec COMMA VarList {
            $$ = insertNode($1, "VarList", @1.first_line, NONTERMINAL);
            $1->brother = $2;
            $2->brother = $3;
        }
        | ParamDec {
            $$ = insertNode($1, "VarList", @1.first_line, NONTERMINAL);
        }
        ;
    
    ParamDec : Specifier VarDec {
            $$ = insertNode($1, "ParamDec", @1.first_line, NONTERMINAL);
            $1->brother = $2;
        }
        ;
    
     /*-----------------------------------------|
     |                Statements                |
     |-----------------------------------------*/
    CompSt : LC DefList StmtList RC {
            $$ = insertNode($1, "CompSt", @1.first_line, NONTERMINAL);
            $1->brother = $2;
            $2->brother = $3;
            $3->brother = $4;
        }
        ;
    
    StmtList : Stmt StmtList {
            $$ = insertNode($1, "StmtList", @1.first_line, NONTERMINAL);
            $1->brother = $2;
        }
        | {
            $$ = insertNode(NULL, "FunDec", yylineno, NONTERMINAL);
        }
    
        ;
        
    Stmt : Exp SEMI {
            $$ = insertNode($1, "Stmt", @1.first_line, NONTERMINAL);
            $1->brother = $2;
        }
        | CompSt {
            $$ = insertNode($1, "Stmt", @1.first_line, NONTERMINAL);
        }
        | RETURN Exp SEMI {
            $$ = insertNode($1, "Stmt", @1.first_line, NONTERMINAL);
            $1->brother = $2;
            $2->brother = $3;
        }
        | IF LP Exp RP Stmt{
            $$ = insertNode($1, "Stmt", @1.first_line, NONTERMINAL);
            $1->brother = $2;
            $2->brother = $3;
            $3->brother = $4;
            $4->brother = $5;
        }
        | IF LP Exp RP Stmt ELSE Stmt {
            $$ = insertNode($1, "Stmt", @1.first_line, NONTERMINAL);
            $1->brother = $2;
            $2->brother = $3;
            $3->brother = $4;
            $4->brother = $5;
            $5->brother = $6;
            $6->brother = $7;
        }
        | WHILE LP Exp RP Stmt {
            $$ = insertNode($1, "Stmt", @1.first_line, NONTERMINAL);
            $1->brother = $2;
            $2->brother = $3;
            $3->brother = $4;
            $4->brother = $5;
        }
        | error RC{ 
            char msg[100];
            sprintf( msg, "error RC:Missing \";\"");
            // printf("8\n");
            myerror( msg );  
        }
    
        ;
    
     /*-----------------------------------------|
     |             Local Definitions            |
     |-----------------------------------------*/
    DefList : Def DefList {
            $$ = insertNode($1, "DefList", @1.first_line, NONTERMINAL);
            $1->brother = $2;
        }
        | {
            $$ = insertNode(NULL, "DefList", yylineno, NONTERMINAL);
        }
        ;
    
    Def : Specifier DecList SEMI {
            $$ = insertNode($1, "Def", @1.first_line, NONTERMINAL);
            $1->brother = $2;
            $2->brother = $3;
        }
    
        ;
    
    DecList : Dec {
            $$ = insertNode($1, "DecList", @1.first_line, NONTERMINAL);
        }
        | Dec COMMA DecList {
            $$ = insertNode($1, "DecList", @1.first_line, NONTERMINAL);
            $1->brother = $2;
            $2->brother = $3;
        }
    
        ;
    
    Dec : VarDec {
            $$ = insertNode($1, "Dec", @1.first_line, NONTERMINAL);
        }
        | VarDec ASSIGNOP Exp {
            $$ = insertNode($1, "Dec", @1.first_line, NONTERMINAL);
            $1->brother = $2;
            $2->brother = $3;
        }
        ;
    
     /*-----------------------------------------|
     |               Expressions                |
     |-----------------------------------------*/
    Exp : Exp ASSIGNOP Exp {
            $$ = insertNode($1, "Exp", @1.first_line, NONTERMINAL);
            $1->brother = $2;
            $2->brother = $3;
        }
        | Exp AND Exp {
            $$ = insertNode($1, "Exp", @1.first_line, NONTERMINAL);
            $1->brother = $2;
            $2->brother = $3;
        }
        | Exp OR Exp {
            $$ = insertNode($1, "Exp", @1.first_line, NONTERMINAL);
            $1->brother = $2;
            $2->brother = $3;
        }
        | Exp RELOP Exp {
            $$ = insertNode($1, "Exp", @1.first_line, NONTERMINAL);
            $1->brother = $2;
            $2->brother = $3;
        }
        | Exp PLUS Exp {
            $$ = insertNode($1, "Exp", @1.first_line, NONTERMINAL);
            $1->brother = $2;
            $2->brother = $3;
        }
        | Exp MINUS Exp {
            $$ = insertNode($1, "Exp", @1.first_line, NONTERMINAL);
            $1->brother = $2;
            $2->brother = $3;
        }
        | Exp STAR Exp {
            $$ = insertNode($1, "Exp", @1.first_line, NONTERMINAL);
            $1->brother = $2;
            $2->brother = $3;
        }
        | Exp DIV Exp {
            $$ = insertNode($1, "Exp", @1.first_line, NONTERMINAL);
            $1->brother = $2;
            $2->brother = $3;
        }
        | LP Exp RP {
            $$ = insertNode($1, "Exp", @1.first_line, NONTERMINAL);
            $1->brother = $2;
            $2->brother = $3;
        }
        | MINUS Exp {
            $$ = insertNode($1, "Exp", @1.first_line, NONTERMINAL);
            $1->brother = $2;
        }
        | NOT Exp {
            $$ = insertNode($1, "Exp", @1.first_line, NONTERMINAL);
            $1->brother = $2;
        }
        | ID LP Args RP {
            $$ = insertNode($1, "Exp", @1.first_line, NONTERMINAL);
            $1->brother = $2;
            $2->brother = $3;
            $3->brother = $4;
        }
        | ID LP RP {
            $$ = insertNode($1, "Exp", @1.first_line, NONTERMINAL);
            $1->brother = $2;
            $2->brother = $3;
        }
        | Exp LB Exp RB {
            $$ = insertNode($1, "Exp", @1.first_line, NONTERMINAL);
            $1->brother = $2;
            $2->brother = $3;
            $3->brother = $4;
        }
        | Exp DOT ID {
            $$ = insertNode($1, "Exp", @1.first_line, NONTERMINAL);
            $1->brother = $2;
            $2->brother = $3;
        }
        | ID {
            $$ = insertNode($1, "Exp", @1.first_line, NONTERMINAL);
        }
        | INT {
            $$ = insertNode($1, "Exp", @1.first_line, NONTERMINAL);
        }
        | FLOAT {
            $$ = insertNode($1, "Exp", @1.first_line, NONTERMINAL);
        }
        | error RB { 
            char msg[100];
            sprintf( msg, "Missing \"]\"");
            // printf("3\n");
            myerror( msg );                // error
        }
        | error INT { 
            char msg[100];
            sprintf( msg, "error INT:Missing \"]\"");
            // printf("3\n");
            myerror( msg );                // error
        }
        | FLOAT error ID{ 
            char msg[100];
            sprintf( msg, "Syntax error.");
            // printf("6\n");
            myerror( msg );  
        }
        | INT error ID{ 
            char msg[100];
            sprintf( msg, "INT error ID:Missing \";\"");
            // printf("7\n");
            myerror( msg );  
        }
        | INT error INT{ 
            char msg[100];
            sprintf( msg, "INT error INT:Missing \";\"");
            // printf("8\n");
            myerror( msg );  
        }
    
        
        ;
    
    Args : Exp COMMA Args {
            $$ = insertNode($1, "CompSt", @1.first_line, NONTERMINAL);
            $1->brother = $2;
            $2->brother = $3;
        }
        | Exp {
            $$ = insertNode($1, "CompSt", @1.first_line, NONTERMINAL);
        }
        ;
    
    %%
    
    #include "lex.yy.c"
    
    int main(int argc, char **argv) {
        if (argc <= 1) return 1;
        FILE *f = fopen(argv[1], "r");
        if (!f) {
            perror(argv[1]);
            return 1;
        }
        yylineno = 1;
        yyrestart(f);
        yyparse();
    
        // Output syntax tree
        f = fopen("output.txt", "w");
        if (!f) {   
            perror(argv[1]);
            return 1;
        }
        if (errors == 0) {
            f = fopen("output.txt", "w");
            printTree(head, 0, f);
        }
    
        return 0;
    }
    
    // Overload, invalidating yyerror function
    void yyerror(char *msg)
    {
        // fprintf(stderr, "Error type B at Line %d: %s\n", yylineno,  msg);
        //  printf( "%d: %s\n", yylineno,  msg);
        // errors++;
    }
    
    // Set custom myerror
    void myerror(char *msg)
    {
        fprintf(stderr, "Error type B at Line %d: %s \n", yylineno,  msg);
        errors++;
    }
    

Posted by Arrow on Wed, 03 Nov 2021 11:17:44 -0700