附件中包含了到目前为止的所有文件,除了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了,所以对应地,AbstractSyntaxNode和Token中的域也要改成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命令,则会产生词法分析器。
语法分析就到此为止了,以后将进入语义分析部分
分享到:
相关推荐
在本篇文章中,我们将深入探讨PL/0语法分析器及其在VC6.0环境下运行的相关知识点。 **1. PL/0语言基础** PL/0是一种极简的、静态类型的命令式编程语言,主要用于演示编译器和解释器的工作原理。它的语法规则简单...
本篇文章将深入探讨如何构建一个自定义的CMM(假设这是一种虚构的中间语言)语法分析器,以及在这个过程中涉及的核心技术和实践经验。 首先,我们需要理解语法分析器的基本工作原理。语法分析器的主要任务是对输入...
《3GWS-Demo汉语语法分析器:编译原理与实现技术详解》 在计算机科学领域,编译器是将高级编程语言转换为机器可理解的低级代码的关键工具。3GWS-Demo汉语语法分析器是专为处理汉语编程语言而设计的一种编译器前端,...
本篇文章将深入探讨C++编译原理中的语法分析器,帮助读者理解其工作原理、设计方法以及实现过程。 一、编译原理概述 编译原理是一门研究如何将高级编程语言转换为机器可执行代码的学科。这一过程通常包括词法分析、...
这篇实验报告主要关注的是编译原理中的两个关键步骤:词法分析和语法分析。实验的目的是通过实际操作来深入理解编译程序的构建过程,包括整体结构、词法分析原理和实现、语法分析原理和递归下降分析方法,以及符号表...
本篇内容将深入探讨“语法分析器”这一主题,特别是使用C语言实现的语法分析器。 首先,我们来了解什么是语法分析。在编译器的工作流程中,语法分析是紧随词法分析之后的阶段。它主要负责检查源代码序列是否符合...
本篇文章将深入探讨LR分析方法,特别是LR(0)分析,以及如何利用它来实现语法分析。 LR分析的核心思想是从左向右读取输入符号串,自底向上地构造语法树。"L"代表“Left-to-right”,表示分析过程是从输入串的左侧...
这篇实验报告详细介绍了如何实现一个LR语法分析器,并提供了源代码和程序流程图。 1. LL(1)文法分析 LL(1)文法是一种前向预测的自底向上分析方法。设计要求包括: - 判断输入文法是否为LL(1)文法。 - 如果是LL(1...
本篇将深入探讨编译原理中的语法分析概念,以及如何在经典开发环境Visual C++ 6.0(简称VC6.0)中进行C++的语法分析。 首先,我们需要了解编译器的基本工作流程,包括词法分析、语法分析、语义分析和代码生成。词法...
在本篇中,我们将深入探讨语法分析这一主题,以及它在编译原理中的重要性。 语法分析是编译器设计的第二阶段,紧跟词法分析之后。它的主要任务是根据语法规则检查源代码的结构,确保源程序符合特定编程语言的语法...
本篇文章将深入探讨如何在Java环境中实现语法分析,并结合具体的实现代码和程序报告来阐述这一过程。 首先,我们要理解Java语法的基本构成,包括关键字、标识符、数据类型、运算符、控制结构等。这些元素构成了Java...
本篇将深入探讨南华大学编译原理实验中的词法分析器和语法分析器的设计,并结合期末复习PPT,全面解析这一领域的关键知识点。 一、词法分析 词法分析,也称扫描器或词法生成器,是编译器的第一步。它的主要任务是...
本篇文章将深入探讨C++实现的语法分析程序,并基于提供的"LL1_syntax.cpp"文件,解析其背后的核心概念和技术。 首先,我们要理解什么是语法分析。在编译过程中,语法分析阶段紧随词法分析之后,其任务是验证源代码...
本篇文章将探讨一个基于Java实现的简易语法分析器,该分析器涵盖了递归、LL和LR三种解析策略,并且提供了一个可执行的jar包。我们将深入分析这些概念,以便更好地理解和应用它们。 首先,我们来了解一下什么是语法...
本篇文章将深入探讨PL0的词法分析和语法分析过程。 词法分析是编译器的第一步,它将源代码中的字符流转换成有意义的符号,即标记(token)。在PL0中,词法分析主要涉及以下几种标记: 1. **标识符(Identifier)**...
本篇文章将深入探讨Java PL/0语法分析器的工作原理、设计与实现,并结合相关标签进行详细阐述。 首先,我们需要了解什么是语法分析器。语法分析器是编译器或解释器的一部分,负责将词法分析器(也称为扫描器)生成...
### 编译原理:LL(1)语法分析器的设计 #### 概述 本文将详细介绍一个简单的LL(1)语法分析器的设计与实现过程。...本篇介绍的LL(1)语法分析器提供了一个基本框架,可用于理解和实现更复杂的语法分析任务。
本篇将详细介绍表驱动的LL(1)语法分析程序的设计、实现及其关键概念。 1.1 目的与意义 设计一个表驱动的LL(1)语法分析程序旨在深化对预测分析法的理解,掌握如何构建和使用预测分析表。这一过程不仅锻炼了编程能力...
本篇文章将重点介绍自底向上的语法分析方法中的算符优先分析法,并通过具体的设计与实现来加深对该方法的理解。 #### 二、算符优先分析的基本概念 算符优先分析是一种自底向上的语法分析技术,适用于具有算符优先...