[语法分析]完结篇

附件中包含了到目前为止的所有文件,除了COOL目录之外。

    语法分析的功能基本上成熟了,调试也完成了,现在剩下将这些东西整合起来成为一个没有调试输出(特别是内存分配调试)的整体了。首先要做的事情是,把COOL中的Queue/Stack这些东西包含进来,就放在datastruct.h中。

#ifndef _DATA_STRUCTURE_H
#define _DATA_STRUCTURE_H

#include"const.h"
#include"COOL/Stack/Stack.h"
#include"COOL/Queue/Queue.h"
#include"COOL/MemoryAllocationDebugger.h"

// blablabla

#endif /* _DATA_STRUCTURE_H */

这样就不用在其它每个文件中都重复地引用这些头文件了。接着,我们可以抽取原来词法分析主文件中的一些函数出来,让语法分析也可以使用,如这些函数。

/* jerry-ui.h */

#ifndef _JERRY_UI_H
#define _JERRY_UI_H

#include<stdio.h>

#include"datastruct.h"

// 原来的 handleFile 用于处理传入编译器的命令行参数
void handleParam(int argc, char* argv[], FILE** out);
int nextChar(void);
unsigned int getLineNumber(void); // 获取行号
void lexicalError(struct Token* token); // 以前词法分析中的error函数,参数列表有改动
void syntaxError(ErrMsg e, struct Token* t);
int isFailed(void); // 是否出错

#ifdef _DEBUG_MODE
#include"jerry-ui.c"
#endif /* _DEBUG_MODE */

#endif /* _JERRY_UI_H */

需要注意的是,以前行号lineNumber和failed是直接可以引用的int值,这样并不规范,所以现在弄成了一个接口函数,在其它文件中只能通过getLineNumber和isFailed进行只读操作,它们现在放在jerry-ui.c中维护了

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#include"jerry-ui.h"

#define HELP_INFO                     \
    "Jerry Compiler.\n"               \
    "Option:\n"                       \
    "    -o <file>: output into <file>"

static unsigned int lineNumber = 1;
static int currentChar;
static int failed = 0;
static FILE* in;

int isFailed(void)
{
    return failed;
}

unsigned int getLineNumber(void)
{
    return lineNumber;
}

void lexicalError(struct Token* token)
{
    fprintf(stderr, "Lexical error @ line %u: `%s'\n"
                    "    %s\n",
            token->line, token->image, token->err);
    failed = 1;
}

void syntaxError(ErrMsg e, struct Token* t)
{
    failed = 1;
    if (END == t->type) {
        fprintf(stderr, "Syntax error at the end of the file.\n"
                        "    %s\n",
                e);
    } else {
        fprintf(stderr, "Syntax error @ line: %u token: `%s'\n"
                        "    %s\n",
                t->line,  t->image, e);
    }
}

int nextChar(void)
{
    currentChar = fgetc(in);
    lineNumber += ('\n' == currentChar);
    if (EOF == currentChar) {
        fclose(in);
    }
    return currentChar;
}

void handleParam(int argc, char* argv[], FILE** out)
{
    if (0 == argc) {
        puts(HELP_INFO);
        exit(0);
    }

    in = fopen(argv[0], "r");
    if (NULL == in) {
        fprintf(stderr, "Usage: %s access error.\n", argv[0]);
        exit(0);
    }
    *out = stdout;

    int i = 1;
    while (i < argc) {
        if (0 == strcmp("-o", argv[i])) { // 检查option. 现在只提供了-o这一个功能,所以只要这样就可以了
            ++i;
            if (i < argc) {
                *out = fopen(argv[i], "w");
                if (NULL == *out) {
                    fprintf(stderr, "Usage: %s access error.\n", argv[i]);
                    exit(0);
                }
                ++i;
                continue;
            } else {
                fprintf(stderr, "No output file specified.\n");
                exit(0);
            }
        }
        fprintf(stderr, "Unknown parameter: %s\n", argv[i]);
        exit(0);
    }
}

因为lineNumber现在换成unsigned int了,所以对应地,AbstractSyntaxNodeToken中的域也要改成unsigned int类型。

    当然,firstToken, nextToken, eofToken这些函数并没有抽取,因为词法和语法分析中这些函数是有显著不同的。如果想编译生成语法分析器或仅编译生成词法分析器,那么可以将这两者分开,并用一个makefile来分开编译

CC=gcc -Wall
# change it if COOL is somewhere else.
COOL=COOL/

UI_SET=jerry-ui.o
LEXICAL_SET=dfa.o
SYNTAX_SET=syntax-node.o lr-analyser.o operation-analyser.o variable-analyser.o Stack.o Queue.o

syntax:Syntax.out
lexical:Lexical.out

jerry-ui.o:jerry-ui.c
	$(CC) -c $<

Lexical.out:jerry-lexical.o $(UI_SET) $(LEXICAL_SET)
	$(CC) -o $@ $^
jerry-lexical.o:jerry-lexical.c
	$(CC) -c $<
dfa.o:dfa.c
	$(CC) -c $<

Syntax.out:jerry-syntax.o $(UI_SET) $(LEXICAL_SET) $(SYNTAX_SET)
	$(CC) -o $@ $^
jerry-syntax.o:jerry-syntax.c
	$(CC) -c $<
syntax-node.o:syntax-node.c
	$(CC) -c $<
lr-analyser.o:lr-analyser.c
	$(CC) -c $<
operation-analyser.o:operation-analyser.c
	$(CC) -c $<
variable-analyser.o:variable-analyser.c
	$(CC) -c $<

Stack.o:$(COOL)Stack/Stack.c
	$(CC) -c $< -o $@
Queue.o:$(COOL)Queue/Queue.c
	$(CC) -c $< -o $@

clean:
	rm *.o

默认的make将产生语法分析器,如果使用make lexical命令,则会产生词法分析器。

    语法分析就到此为止了,以后将进入语义分析部分

你可能感兴趣的:(C++,c,UI,C#,Access)