Cepheusss 2023-09-06 17:37 采纳率: 33.3%
浏览 2

使用lex和yacc尝试转换一个简单结构体中遇见过的问题


/*lex.l*/
%{
#include "y.tab.h"
%}

%%
"typedef"   { return TYPEDEF; }
"struct"    { return STRUCT; }
"char"      { return CHAR; }
"short"     { return SHORT; }
"int"       { return INT; }
"float"     { return FLOAT; }
"double"    { return DOUBLE; }
[a-zA-Z_][a-zA-Z0-9_]* { yylval.str = strdup(yytext); return IDENTIFIER; }
";"         { return SEMICOLON; }
"{"         { return LBRACE; }
"}"         { return RBRACE; }
"["         { return LBRACKET; }
"]"         { return RBRACKET; }
[ \t\n]     {}
.           {}

%%
/*yacc.y*/
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lex.yy.c"

extern int yylex();
extern FILE* yyin;
void yyerror(const char *s);

char* typeDefName = NULL;

int yywrap() {
    return 1;
}
%}

%union {
    char* str;
}

%token TYPEDEF STRUCT CHAR SHORT INT FLOAT DOUBLE IDENTIFIER SEMICOLON LBRACE RBRACE LBRACKET RBRACKET
%type <str> structDeclaration fieldDeclaration

%%

program:
    structDeclaration { 
        printf("public class %s {\n", $1);
    }  
    | 
    ;

struct_declaration:
    TYPEDEF STRUCT IDENTIFIER '\n' LBRACE field_declaration RBRACE IDENTIFIER SEMICOLON {
        printf("}\n");)
    }
    |
    ;

field_declaration:
    INT IDENTIFIER SEMICOLON {
        printf("    private int %s;\n", $2);
    }
    | CHAR IDENTIFIER LBRACKET INT RBRACKET SEMICOLON {
        printf("    private String %s;\n", $2);
    }
    | SHORT IDENTIFIER SEMICOLON {
        printf("    private short %s;\n", $2);
    }
    | FLOAT IDENTIFIER SEMICOLON {
        printf("    private float %s;\n", $2);
    }
    | DOUBLE IDENTIFIER SEMICOLON {
        printf("    private double %s;\n", $2);
    }
    ;

%%

void yyerror(const char *s) {
    fprintf(stderr, "Error: %s\n", s);
}

int main(int argc, char *argv[]) {
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <input_file>\n", argv[0]);
        return 1;
    }

    yyin = fopen(argv[1], "r");
    if (!yyin) {
        perror("fopen");
        return 1;
    }

    yyparse();

    fclose(yyin);
    free(typeDefName);
    return 0;
}

在执行的时候,lex文件可以执行,但是yacc yac.y时会报错, $2 (IDENTIFIER) is untyped, 这里卡住了,不明白什么意思、希望各位佬解答

  • 写回答

1条回答 默认 最新

  • CSDN-Ada助手 CSDN-AI 官方账号 2023-09-06 20:21
    关注

    【以下回答由 GPT 生成】

    为了改进这段代码,我会提出以下几点建议:

    1. 在lex.l中,为了提高代码的可读性和可维护性,建议将每个关键字单独放在一个规则中,并添加一个通用的规则来匹配标识符。另外,使用yytext动态分配内存时,最好在适当的时候释放内存。

    这是改进后的lex.l代码:

    /*lex.l*/
    %{
    #include "y.tab.h"
    %}
    
    %%
    "typedef" { return TYPEDEF; }
    "struct" { return STRUCT; }
    "char" { return CHAR; }
    "short" { return SHORT; }
    "int" { return INT; }
    "float" { return FLOAT; }
    "double" { return DOUBLE; }
    "{" { return LBRACE; }
    "}" { return RBRACE; }
    "[" { return LBRACKET; }
    "]" { return RBRACKET; }
    ";" { return SEMICOLON; }
    [a-zA-Z_][a-zA-Z0-9_]* {
      yylval.str = strdup(yytext);
      return IDENTIFIER;
    }
    [ \t\n] {}
    . {}
    
    %%
    
    1. 在yacc.y中,为了使代码更加清晰和易于理解,建议将声明和定义分开处理,并在适当的时候释放内存。此外,在yacc文件中应该使用%type指令来为非终结符规则指定返回类型。

    这是改进后的yacc.y代码:

    /*yacc.y*/
    %{
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "lex.yy.c"
    
    extern int yylex();
    extern FILE* yyin;
    void yyerror(const char *s);
    
    char* typeDefName = NULL;
    
    int yywrap() {
        return 1;
    }
    %}
    
    %union {
      char* str;
    }
    
    %token TYPEDEF STRUCT CHAR SHORT INT FLOAT DOUBLE IDENTIFIER SEMICOLON LBRACE RBRACE LBRACKET RBRACKET
    %type <str> structDeclaration fieldDeclaration
    
    %{
      void freeString(char* str) {
        if (str != NULL) {
          free(str);
        }
      }
    %}
    
    %%
    
    program: structDeclaration
            ;
    
    structDeclaration: TYPEDEF STRUCT IDENTIFIER '\n' LBRACE fieldDeclaration RBRACE IDENTIFIER SEMICOLON {
      printf("public class %s {\n", $3);
      freeString($7);
    }
                      ;
    
    fieldDeclaration: INT IDENTIFIER SEMICOLON {
      printf("    int %s;\n", $2);
      freeString($2);
    }
                     ;
    
    %%
    
    void yyerror(const char *s) {
      fprintf(stderr, "%s\n", s);
    }
    
    int main() {
      yyin = fopen("input.txt", "r"); // 假设输入文件名为input.txt
      yyparse();
      fclose(yyin);
      return 0;
    }
    

    在以上代码中,我添加了一个名为freeString的辅助函数,用于释放动态分配的字符串的内存。此外,我还添加了用于打印错误消息的yyerror函数,并在主函数中打开并关闭输入文件。

    这些改进应该能够提高代码的可读性和可维护性,并解决一些潜在的内存泄漏问题。


    如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^
    评论

报告相同问题?

问题事件

  • 创建了问题 9月6日

悬赏问题

  • ¥20 Wpf Datarid单元格闪烁效果的实现
  • ¥15 图像分割、图像边缘提取
  • ¥15 sqlserver执行存储过程报错
  • ¥100 nuxt、uniapp、ruoyi-vue 相关发布问题
  • ¥15 浮窗和全屏应用同时存在,全屏应用输入法无法弹出
  • ¥100 matlab2009 32位一直初始化
  • ¥15 Expected type 'str | PathLike[str]…… bytes' instead
  • ¥15 三极管电路求解,已知电阻电压和三级关放大倍数
  • ¥15 ADS时域 连续相位观察方法
  • ¥15 Opencv配置出错