return0;
}
1.4实验结果
实验结果输出到.out文件中,截图示例:
2借助Flex/Bison进行语法分析
2.1实验内容
利用附录提供的C语言文法的相关参考资料,利用Yacc/Bison编写一个C语言分析器。
具体内容:
1)利用语法分析器生成工具Bison编写一个语法分析程序,与词法分析器结合能够根据语言的上下文无关文法,识别输入的单词序列是否文法的句子
2)利用附录提供的C语言文法的相关参考资料,利用Yacc/Bison编写一个C语言分析器。
2.2实验要求
1)编写Bison源文件,实现C语言的语法分析功能,最后上机调试。
2)要求编写一个测试程序,以给定的测试文件作为输入,输出运行结果到输出文件中。
2.3程序代码
由于本实验的lex源文件和yacc源文件代码较长而且在“实验附录:
C语言相关文法”文件夹中已经给出相关源码的链接,由于报告篇幅限制不再贴出源码
Test.测试文件源码:
voidmain()
{inti=0;intj=0;
}
voidt1()
{inti=0;
}
typedefunsignedintuint;
uintxx;
uintyy;
2.4实验步骤
1、flex-linput.lex
bison-dcgrammar-new.y(产生头文件和.c文件)
2、comment函数调用yyinput,编译会有链接错误,解决方法一,将lex.yy.c中的yyinput函数定义拷贝一份到input.lex,重命名为my_yyinput,
或者将lex.yy.c中的
#ifdef__cplusplus
staticintyyinput()
#else
staticintinput()
#endif
改为staticintyyinput()
上述问题出现的情形:
词法分析器的后缀名为.c,而不是.cpp
3、cgrammar-new.tab.c中如下程序段
/*----------.
|yyparse.|
`----------*/
#ifdefYYPARSE_PARAM
#ifdefined(__STDC__)||defined(__cplusplus)
intyyparse(void*YYPARSE_PARAM)
#else
intyyparse(YYPARSE_PARAM)
void*YYPARSE_PARAM;
#endif
#else/*!
YYPARSE_PARAM*/
#ifdefined(__STDC__)||defined(__cplusplus)
int
yyparse(void)
#else
int
yyparse();
#endif
#endif
改为
intyyparse()或者intyyparse(void)
4、lex.yy.c中,将下面语句注释
if(!
yyin)
yyin=stdin;
5、解析之前,设置yyin为输入文件指针
externFILE*yyin;
if(!
(yyin=fopen(filename,"r"))){
printf("thefilenotexist\n");
exit(0);
}
2.5实验结果
实验结果输出到.out文件中,截图示例:
3Flex/Bison综合实验
3.1实验内容
使用flex和bison开发了一个具有全部功能的桌面计算器,能够支持变量,过程,循环和条件表达式,使它成为一个虽然短小但是具有现实意义的编译器。
重点学习抽象语法树的用法,它具有强大而简单的数据结构来表示分析结果
3.2计算器具体需要实现的功能
变量命名;实现赋值功能;实现比较表达式(大于、小于、等于等等)实现if/then/else和do/while的流程控制;用户可以自定义函数;简单的错误恢复机制
3.3实验要求
编写Flex/Bison源文件,实现C语言的语法分析功能,最后上机调试。
要求编写一个测试程序:
1)首先自定义两个函数sq和avg,sq函数使用Newton方法来迭代计算平方根;avg函数计算两个数值的平均值。
2)利用定义好的函数进行计算,得到计算结果并显示出来
3.4程序代码
Cal.l源码
%{
#include"cal.tab.h"
%}
%optionnoyywrap
integer[0-9]+
dreal([0-9]*"."[0-9]+)
ereal([0-9]*"."[0-9]+[EedD][+-]?
[0-9]+)
real{dreal}|{ereal}
nl\n
plus"+"
minus"-"
times"*"
divide"/"
lp"("
rp")"
module"%"
power"^"
%%
[\t];/*skipanyblanks*/
{integer}{sscanf(yytext,"%d",&yylval.integer);
returnINTEGER;}
{real}{sscanf(yytext,"%lf",&yylval.real);/*yylval=atof(yytext);itdoesn'tworkunderMSVSC*/
returnREAL;}
{plus}{returnPLUS;}
{minus}{returnMINUS;}
{times}{returnTIMES;}
{divide}{returnDIVIDE;}
{module}{returnMODULE;}
{power}{returnPOWER;}
{lp}{returnLP;}
{rp}{returnRP;}
{nl}{returnNL;}
.{returnyytext[0];}
Cal.y源码
%{
#include
#include
%}
%union{doublereal;/*realvalue*/
intinteger;/*integervalue*/}
%tokenREAL
%tokenINTEGER
%startlines
%tokenNUMBERNL
%tokenPLUSMINUSTIMESDIVIDEMODULEPOWERLPRP
%typerexpr
%typeiexpr
%leftPLUSMINUS/*leftassociative*/
%leftTIMESDIVIDEMODULE/*leftassociative*/
%leftPOWER
%leftUNARYMINUS
%%
lines:
/*nothing*/
|lineslineNL
|lineserrorNL
{yyerror();yyerrok;};
line:
iexpr
{printf("%d\n",$1);}
|rexpr
{printf("%lf\n",$1);};
iexpr:
INTEGER
{$$=$1;}
|iexprPLUSiexpr
{$$=$1+$3;}
|iexprMINUSiexpr
{$$=$1-$3;}
|iexprTIMESiexpr
{$$=$1*$3;}
|iexprDIVIDEiexpr
{if($3)
$$=$1/$3;
else{$$=$1;
printf(stderr,"%d.%d-%d.%d:
divisionbyzero",
@3.first_line,@3.first_column,
@3.last_line,@3.last_column);}}
|iexprMODULEiexpr
{$$=$1%$3;}
|iexprPOWERiexpr
{$$=pow($1,$3);}
|MINUSiexpr%precUNARYMINUS
{$$=-$2;}
|LPiexprRP
{$$=$2;}
|LPiexprerror
{$$=$2;yyerror("missing')'");yyerrok;}
|PLUSiexpr%precUNARYMINUS
{$$=$2;};
rexpr:
REAL
{$$=$1;}
|rexprPLUSrexpr
{$$=$1+$3;}
|rexprMINUSrexpr
{$$=$1-$3;}
|rexprTIMESrexpr
{$$=$1*$3;}
|rexprDIVIDErexpr
{if($3)$$=$1/$3;
else
{$$=$1;
printf(stderr,"%d.%d-%d.%d:
divisionbyzero",
@3.first_line,@3.first_column,
@3.last_line,@3.last_column);}}
|rexprPOWERrexpr
{$$=pow($1,$3);}
|LPrexprRP
{$$=$2;}
|LPrexprerror
{$$=$2;yyerror("missing')'");yyerrok;}
|MINUSrexpr%precUNARYMINUS
{$$=-$2;}
|PLUSrexpr%precUNARYMINUS
{$$=$2;}
|iexprPLUSrexpr
{$$=(double)$1+$3;}
|iexprMINUSrexpr
{$$=(double)$1-$3;}
|iexprTIMESrexpr
{$$=(double)$1*$3;}
|iexprDIVIDErexpr
{if($3)$$=(double)$1/$3;
else
{$$=$1;
printf(stderr,"%d.%d-%d.%d:
divisionbyzero",
@3.first_line,@3.first_column,
@3.last_line,@3.last_column);}}
|iexprPOWERrexpr
{$$=pow((double)$1,$3);}
|rexprPLUSiexpr
{$$=$1+(double)$3;}
|rexprMINUSiexpr
{$$=$1-(double)$3;}
|rexprTIMESiexpr
{$$=$1*(double)$3;}
|rexprDIVIDEiexpr
{if($3)
$$=$1/(double)$3;
else
{$$=$1;
printf(stderr,"%d.%d-%d.%d:
divisionbyzero",
@3.first_line,@3.first_column,
@3.last_line,@3.last_column);}}
|rexprPOWERiexpr
{$$=pow($1,(double)$3);};
%%
voidmain()
{
yyparse();}
intyyerror(char*msg)
{printf("Error:
%sencountered\n",msg);}
3.5实验结果
实验结果截图:
4(操作系统实验)lib0:
熟悉实验环境
4.1实验目的
1)了解操作系统开发实验环境
2)熟悉命令行方式的编译、调试工程
3)掌握基于硬件模拟器的调试技术
4)熟悉C语言编程和指针的概念
5)了解X86汇编语言
4.2实验环境搭建
1)在线实验--基于"实验楼"在线平台
2)Windows下基于MingW进行实验
3)Windows下基于VirtualBoxorVMWare进行实验
4)在MACOS下进行实验
5)手动在物理PC中安装环境
4.3GCC编译练习
采用实验环境:
在线实验--基于"实验楼"在线平台
gcc示例:
#include
intmain(void)
{
printf("hello!
\n");
return0;
}
在实验环境中右键->从模板创建->空文件,将上述示例代码输入
1)保存为hello.c
打开命令行,输入以下命令:
2)编译:
gcc-Wallhello.c-ohello
3)执行:
./hello
操作及结果截图:
4.4GDB调试练习
1)输入命令:
gcc-ohellohello.c–g进行编译
2)输入命令:
gdb进入调试
3)依次输入以下命令熟悉gdb调试
filehello:
进入hello文件
run:
运行hello
break1:
在第一行插入断点
next:
单步执行下一行语句
clear1:
清除第一行的断点
list:
显示hello文件的内容
quit:
退出gdb调试
对应命令执行结果截图:
GDB的其它调试命令补充:
next:
单步到程序源代码的下一行,不进入函数。
nexti:
单步一条机器指令,不进入函数。
step:
单步到下一个不同的源代码行(包括进入函数)。
stepi:
单步一条机器指令
他们功能各不相同,区别在于单步的“跨度”上。
5(操作系统实验)lib1:
启动操作系统
5.1实验目的
操作系统是一个软件,也需要通过某种机制加载并运行它。
在这里我们将通过另外一个更加简单的软件-bootloader来完成这些工作。
为此,我们需要完成一个能够切换到x86的保护模式并显示字符的bootloader,为启动操作系统ucore做准备。
lab1提供了一个非常小的bootloader和ucoreOS,整个bootloader执行代码小于512个字节,这样才能放到硬盘的主引导扇区中。
通过分析和实现这个bootloader和ucoreOS,读者可以了解到:
1)计算机原理
CPU的编址与寻址:
基于分段机制的内存管理
CPU的中断机制
外设:
串口/并口/CGA,时钟,硬盘
2)Bootloader软件
编译运行bootloader的过程
调试bootloader的方法
PC启动bootloader的过程
ELF执行文件的格式和加载
外设访问:
读硬盘,在CGA上显示字符串
3)ucoreOS软件
编译运行ucoreOS的过程
ucoreOS的启动过程
调试ucoreOS的方法
函数调用关系:
在汇编级了解函数调用栈的结构和处理过程
中断管理:
与软件相关的中断处理
外设管理:
时钟
5.2实验内容
lab1中包含一个bootloader和一个OS。
这