代码之家  ›  专栏  ›  技术社区  ›  Jay Lee

使用yacc/bison和tab进行源代码外构建。h最佳实践

  •  0
  • Jay Lee  · 技术社区  · 4 年前

    我正试图在一个使用GNU bison&用于解析和词法分析的flex。

    构建是由GNU Make管理的,在我将逻辑与主逻辑分离之前,一切都进行得很顺利 .y 提交给一个新的 .c 文件 Makefile是从 this post .

    主要问题是 .tab.h 由bison生成,并在生成目录中生成: ./build/src/parser.tab.h .

    我设法以一种特别的方式解决了这个问题,包括 .标签。H 使用相对路径 #include "../build/src/parser.tab.h" 加上 .tab.c 到C文件的依赖项。

    这被认为是一种好的做法吗? 有没有办法在Makefile中隐式声明这一点和/或包含生成的 .标签。H 文件

    这是我的C文件:

    #include "../build/src/parser.tab.h"
    
    int main(int argc, char *argv[])
    {
        yyparse();
        return 0;
    }
    

    Makefile :

    TARGET_EXEC := parser
    
    BUILD_DIR := ./build
    SRC_DIRS := ./src
    
    SRCS := $(shell find $(SRC_DIRS) -name *.c -or -name *.y -or -name *.l)
    OBJS := $(SRCS:%=$(BUILD_DIR)/%.o)
    DEPS := $(OBJS:.o=.d)
    
    INC_DIRS := $(shell find $(SRC_DIRS) -type d)
    INC_FLAGS := $(addprefix -I,$(INC_DIRS))
    
    CC := gcc
    CFLAGS := -O0 -Wall -Wextra -Wpedantic -std=c17
    CPPFLAGS := $(INC_FLAGS) -MMD -MP
    LDFLAGS := -ly -ll
    
    YACC := bison
    YFLAGS := -d
    
    LEX := flex
    LFLAGS :=
    
    $(BUILD_DIR)/$(TARGET_EXEC): $(OBJS)
        $(CC) $(OBJS) -o $@ $(LDFLAGS)
    
    $(BUILD_DIR)/%.c.o: %.c build/src/parser.tab.c
        mkdir -p $(dir $@)
        $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
    
    %.y.o: %.tab.c
        mkdir -p $(dir $@)
        $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
    
    %.l.o: %.yy.c
        mkdir -p $(dir $@)
        $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
    
    $(BUILD_DIR)/%.tab.c: %.y
        mkdir -p $(dir $@)
        $(YACC) $(YFLAGS) $< -o $@
    
    $(BUILD_DIR)/%.yy.c: %.l
        mkdir -p $(dir $@)
        $(LEX) $(LFLAGS) -o $@ $<
    
    .PHONY: clean
    clean:
        rm -r $(BUILD_DIR)
    
    -include $(DEPS)
    

    这里是MWE lexer&解析器:

    %{
    #include "parser.tab.h"
    #include <stdio.h>
    %}
    ws  [ \t]+
    %%
    {ws}    { ; }   // skip whitespaces
    .   { printf("unknown token %c\n", yytext[0]); }
    
    %%
    prgm: ;
    

    树在前&之后:

    .
    ├── Makefile
    ├── build
    │   ├── parser
    │   └── src
    │       ├── lexer.l.d
    │       ├── lexer.l.o
    │       ├── lexer.yy.c
    │       ├── main.c.d
    │       ├── main.c.o
    │       ├── parser.tab.h
    │       ├── parser.y.d
    │       └── parser.y.o
    └── src
        ├── lexer.l
        ├── main.c
        └── parser.y
    
    .
    ├── Makefile
    └── src
        ├── lexer.l
        ├── main.c
        └── parser.y
    
    0 回复  |  直到 4 年前
        1
  •  2
  •   MadScientist    4 年前

    首先,您的makefile比需要的更混乱,因为您使用的是 $(BUILD_DIR) 变量,并使用硬编码 build 在其他地方:在任何地方使用变量。

    其次,不应该在源文件中包含路径。这意味着,无论何时更改makefile以移动某些内容,都必须编辑源文件。

    相反,只需将搜索头文件的路径添加到编译器命令行。你已经有了 INC_FLAGS 变量,该变量包含告诉编译器在何处查找头的选项;只需添加一个新的:

    INC_FLAGS := $(addprefix -I,$(INC_DIRS)) -I$(BUILD_DIR)/src
    

    现在你可以用 #include "y.tab.h" 在你的源头。