原理,汉语词语,拼音是yuán lǐ,意思是具有普遍意义的最基本的规律, 以下是为大家整理的关于实验报告的实验原理怎么写3篇 , 供大家参考选择。
实验报告的实验原理怎么写3篇
实验报告的实验原理怎么写篇1
实验十九 滤波法及数字锁相环法位同步提取实验
一、实验目的1、掌握滤波法提取位同步信号的原理及其对信息码的要求。
2、掌握用数字锁相环提取位同步信号的原理及其对信息代码的要求。
3、掌握位同步器的同步建立时间、同步保持时间、位同步信号同步抖动等概念。
二、实验器材1、主控&信号源、13、8号模块 各一块
2、双踪示波器 一台
3、连接线 若干
三、实验原理1、滤波法位同步提取实验原理框图
滤波法位同步提取实验框图
2、滤波法位同步提取实验框图说明
将单刀双掷开关S2上拨,选择滤波法位同步提取电路,输入HDB3单极性码信号经一个256K窄带滤波器,滤出同步信号分量,通过门限判决后提取位同步信号。但由于有其他频率成分的干扰,导致时钟有些部分的占空比不为50%,因此需要通过模拟锁相环进行平滑处理;数字的256K时钟经过4分频之后,已经得到一定的平滑效果,送入CD4046鉴相输入A脚的是64KHz的时钟信号,当CD4046处于同步状态时,鉴相器A脚的时钟频率及相位应该与鉴相器B脚的相同。由于鉴相器B脚的时钟是VCO经8分频得到的。因此,VCO输出的频率为512K。
3、数字锁相环法位同步提取实验原理框图
word/media/image2_1.png
数字锁相环位同步提取实验原理框图
4、数字锁相环法位同步提取实验框图说明
锁相法位同步提取是在接收端利用锁相环电路比较接收码元和本地产生的位同步信号的相位,并调整位同步信号的相位,最终获得准确的位同步信号。4位拨码开关S3设置BCD码控制分频比,从而控制提取的位同步时钟频率,例如设置分频频率“0000”输出4096KHz频率,“0011”输出512KHz频率,“0100”输出256KHz频率,“0111”输出32KHz频率。。
数字锁相环(DPLL)是一种相位反馈控制系统。它根据输入信号与本地估算时钟之间的相位误差对本地估算时钟的相位进行连续不断的反馈调节,从而达到使本地估算时钟相位跟踪输入信号相位的目的。DPLL 通常有三个组成模块: 数字鉴相器(DPD)、数字环路滤波器(DLF)、 数控振荡器(DCO)。根据各个模块组态的不同, DPLL 可以被划分出许多不同的类型。根据设计的要求,本实验系统采用超前滞后型数字锁相环(LL-DPLL)作为解决方案。在LL- DPLL中,DLF 用双向计数逻辑和比较逻辑实现,DCO 采用“加”、“扣”脉冲式数控振荡器。这样设计出来的DPLL具有结构简洁明快,参数调节方便,工作稳定可靠的优点。DPLL实现框图如下:
word/media/image3_1.png
数字锁相环框图
下面就对数字锁相环的各个组成模块的详细功能、内部结构以及对外接口信号进行说明:
①超前-滞后型数字鉴相器
与一般DPLL 的DPD的设计不同,位同步DPLL 的DPD需要排除位流数据输入连续几位码值保持不变的不利影响。LL-DPD为二元鉴相器,在有效的相位比较结果中仅给出相位超前或相位滞后两种相位误差极性, 而相位误差的绝对大小固定不变。LL-DPD通常有两种实现方式: 微分型LL-DPD和积分型LL-DPD。积分型LL-DPD具有优良的抗干扰性能,而它的结构和硬件实现都比较复杂。微分型LL- DPD 虽然抗干扰能力不如积分型LL-DPD, 但是结构简单,硬件实现比较容易。本实验采用微分型LL-DPD, 将环路抗噪声干扰的任务交给DLF模块负责。
word/media/image4_1.png
LL-DPD模块内部结构与对外接口信号
如图所示,LL-DPD在ClkEst跳变沿(含上升沿和下降沿)处采样DataIn上的码值, 寄存在Mem中。在ClkEst下降沿处再将它们对应送到两路异或逻辑中,判断出相位误差信息并输出。Sign 给出相位误差极性,即ClkEst相对于DataIn是相位超前(Sign=1)还是滞后(Sign=0)。AbsVal 给出相位误差绝对值:若前一位数据有跳变,则判断有效,以AbsVal输出1表示;否则,输出0表示判断无效。 下图显示了LL-DPD模块的仿真波形图。
LL-DPD模块输入输出关系仿真波形图
②数字环路滤波器(DLF)
DLF用于滤除因随机噪声引起的相位抖动,并生成控制DCO 动作的控制指令。本实验实现的DLF内部结构及其对外接口信号如下图所示。
DLF模块内部结构与对外接口信号
滤波功能用加减计数逻辑CntLgc实现,控制指令由比较逻辑CmpLgc生成。在初始时刻,CntLgc被置初值M/2。前级LL-DPD模块送来的相位误差PhsDif在CntLgc中作代数累加。在计数值达到边界值0或M后,比较逻辑CmpLgc将计数逻辑CntLgc同步置回M/2,同时相应地在Deduct或Insert引脚上输出一高脉冲作为控制指令。随机噪声引起的LL-DPD相位误差输出由于长时间保持同一极性的概率极小,在CntLgc中会被相互抵消,而不会传到后级模块中去,达到了去噪滤波的目的。计数器逻辑CntLgc的模值M 对DPLL的性能指标有着显著地影响。加大模值M,有利于提高DPLL的抗噪能力,但是会导致较大的捕捉时间和较窄的捕捉带宽。减小模值M 可以缩短捕捉时间,扩展捕捉带宽,但是降低了DPLL的抗噪能力。根据理论分析和调试实践,确定M为1024,图中计数器数据线宽度w可以根据M确定为10。
③数控振荡器(DCO)
DCO的主要功能是根据前级DLF模块输出的控制信号Deduct和Insert生成本地估算时钟ClkEst,这一时钟信号即为DPLL恢复出来的位时钟。同时,DCO还产生协调DPLL内各模块工作的时钟,使它们能够协同动作。要完成上述功能,DCO 应有三个基本的组成部分:高速振荡器(HsOsc)、相位调节器(PhsAdj)、分频器(FnqDvd),如下图所示。
DCO模块内部结构与对外接口信号
高速振荡器(HsOsc)提供高速稳定的时钟信号Clk,该时钟信号有固定的时钟周期,周期大小即为DPLL 在锁定状态下相位跟踪的精度,同时,它还影响DPLL 的捕捉时间和捕捉带宽。考虑到DPLL 工作背景的要求,以及尽量提高相位跟踪的精度以降低数据接收的误码率,取HsOsc输出信号Clk频率为所需提取位时钟信号的16倍。若取HsOsc输出信号Clk64MHz的周期为15.625ns,即高速振荡器HsOsc的振荡频率为64MHz。
PhsAdj在控制信号Deduct和Insert上均无高脉冲出现时,仅对Osc输出的时钟信号作4分频处理,从而产生的Clk16MHz时钟信号将是严格16MHz 的。当信号Deduct 上有高脉冲时,在脉冲上升沿后,PhsAdj会在时钟信号Clk16MHz的某一周期中扣除一个Clk64Mhz时钟周期,从而导致Clk16MHz时钟信号相位前移。当在信号Insert上有高脉冲时,相对应的处理会导致Clk16MHz时钟信号相位后移。下图为相位调节器单元经功能编译仿真后的波形图。
word/media/image8_1.png
DCO模块相位调节器PhsAdj单元输入输出关系
引入分频器FnqDvd的目的主要是为DPLL中DLF模块提供时钟控制,协调DLF与其它模块的动作。分频器FnqDvd用计数器实现,可以提供多路与输入位流数据有良好相位同步关系的时钟信号。在系统中,分频器FnqDvd提供8路输出ClksSyn[7..0]。其中,ClksSyn1即为本地估算时钟ClkEst,也即恢复出的位时钟;ClksSyn0即为DLF模块的计数时钟ClkCnt,其速率是ClkEst的两倍,可以加速计数,缩短DPLL 的捕捉时间,并可扩展其捕捉带宽。
四、实验步骤实验项目一 滤波法位同步电路带通滤波器幅频特性测量。
概述:该项目是通过改变输入信号的频率,观测信号经滤波后对应输出幅度,从而了解并绘制滤波器的幅频特性。
1、关电,按表格所示进行连线。
2、开电,设置主控,选择【信号源】→【输出波形】。设置输出波形为正弦波,调节相应旋钮,使其输出频率为200KHz,峰峰值3V。
3、此时系统初始状态为:输入信号为频率200KHz、幅度3V的正弦波。
4、实验操作及波形观测。
分别观测13号模块的“滤波法位同步输入”和“BPF-Out”,改变信号源的频率,测量“BPF-Out”的幅度填入下表,并绘制幅频特性曲线。
实验项目二 滤波法位同步恢复观测
概述:该项目是通过比较和观测滤波法位同步电路中各点幅度及相位,探讨滤波法位同步的提取原理以及影响因素。
1、关电,按表格所示进行连线。
2、开电,设置主控菜单,选择【信号源】→【通信原理】→【滤波法及数字锁相环位同步法提取】。将13号模块S2拨上。将S4拨为1000。
3、此时系统初始状态为:输入PN为256K。
4、实验操作及波形观测。
(1)以“BPF-Out”为触发,观测“门限判决输出”,记录波形。
思考:分析在什么情况下门限判决输出的时钟会不均匀,为什么?
(2)以“BPF-Out”为触发,观测“鉴相输入1”,记录波形。
(3)对比“门限判决输出”和“鉴相输入1”的波形。
思考:分析时钟不均匀的情况是否有所改善。
(4)对比观测“鉴相输入1”和“鉴相输入2”,记录波形。比较两路波形的幅度和相位。
(5)对比观测“滤波法位同步输入”和“BS1”,观测恢复的位同步信号。
实验项目三 数字锁相环法位同步观测
概述:该项目是通过比较和观测数字锁相环位同步电路中各点相位超前、延时以及抖动情况,探讨数字锁相环法位同步的提取原理。
1、关电,按表格所示进行连线。
2、开电,设置主控菜单,选择【信号源】→【通信原理】→【滤波法及数字锁相环位同步法提取】。
3、此时系统初始状态为: PN码速率256K。
4、实验操作及波形观测。
(1)观测13模块的“数字锁相环输入”和“输入跳变指示”。观测当“数字锁相环输入”没有跳变和有跳变时“输入跳变指示”的波形。
(2)观测13模块的“数字锁相环输入”和“鉴相输出”。观测相位超前滞后的情况。
(3)观测13模块的“插入指示”和“扣除指示”。
思考:分析波形有何特点,为什么出现这种情况。
(4)以信号源模块的“CLK”为触发,观测13号模块的“BS2”。
思考:BS2恢复的时钟是否有抖动的情况,为什么?试分析BS2抖动的区间有多大?如何减小这个抖动的区间?
五、实验报告1、对实验思考题加以分析,按照要求做出回答,并尝试画出本实验的电路原理图。
2、结合实验波形分析数字锁相环原理。
实验报告的实验原理怎么写篇2
微机原理
实验报告
学校:湖北文理学院、
班级:电子1413
姓名:杨仕浩
学号:2014111347
指导老师:吉向东
实验一两个多位十进制数相加的实验
一、实验目的
学习数据传送和算术运算指令的用法
熟悉在PC机上建立、汇编、链接、调试和运行汇编语言程序的过程。
二、实验内容
将两个多位十进制数相加,要求被加数和加数均以ASCII码形式各自顺序存放在以DATA1、DATA2为首的5个内存单元中(低位在前),结果送回DATA1处。
三、程序框图
四、实验程序清单
DATA SEGMENT
DATA1 DB 33H,39H,31H,37H,34H;被加数
DATA1END EQU $-1
DATA2 DB 34H,35H,30H,38H,32H;加数
DATA2END EQU $-1
SUM DB 5 DUP(?)
DATA ENDS
STACK SEGMENT
STA DB 20 DUP(?)
TOP EQU LENGTH STA
STACK ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:STACK,ES:DATA
START: MOV AX,DATA
MOV DS,AX
MOV AX,STACK
MOV SS,AX
MOV AX,TOP
MOV SP,AX
MOV SI,OFFSET DATA1END
MOV DI,OFFSET DATA2END
CALL ADDA
MOV AX,4C00H
INT 21H
ADDA PROC NEAR
MOV DX,SI
MOV BP,DI
MOV BX,05H
AD1: SUB BYTE PTR [SI],30H
SUB BYTE PTR [DI],30H
DEC SI
DEC DI
DEC BX
JNZ AD1
MOV SI,DX
MOV DI,BP
MOV CX,05H
CLC
AD2: MOV AL,[SI]
MOV BL,[DI]
ADC AL,BL
AAA
MOV [SI],AL
DEC SI
DEC DI
LOOP AD2
MOV SI,DX
MOV DI,BP
MOV BX,05H
AD3: ADD BYTE PTR [SI],30H
ADD BYTE PTR [DI],30H
DEC SI
DEC DI
DEC BX
JNZ AD3
RET
ADDA ENDP
CODE ENDS
END START
5、实验结果
6、实验结果分析
7、实验心得体会
经过这次实验我学会了如何使用命令提示符,并学会了如何用命令提示符运行指令
8、在本次试验中完成了两个两位十进制数的相加,了解了数据传送和算术运算指令的使用方法。
实验二排序实验
一、实验目的
掌握用汇编语言编写排序程序的思路和方法。
二、实验内容
将指定内存出开始的数据按从大到小的顺序排列。第一个数字表示数据的个数。
三、程序流程图
图 3-2
四、程序清单
DATA SEGMENT
ADDR DW 8,234,35,67,876,54,39,765,237
DATA ENDS
STACK SEGMENT
STA DW 32 DUP(?)
TOP DW ?
STACK ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,ES:DATA,SS:STACK
START: MOV AX,DATA
MOV DS,AX
MOV ES,AX
MOV AX,STACK
MOV SS,AX
MOV SP,TOP
MOV CX,WORD PTR ADDR[0]
DEC CX
LOOP1: MOV DI,CX
MOV BX,2
LOOP2: MOV AX,WORD PTR ADDR[BX]
CMP AX,WORD PTR ADDR[BX+2]
JGE CCC
XCHG AX,WORD PTR ADDR[BX+2]
MOV WORD PTR ADDR[BX],AX
CCC: ADD BX,2
LOOP LOOP2
MOV CX,DI
LOOP LOOP1
EXIT: MOV AX,4C00H
INT 21H
CODE ENDS
END START
5、实验结果
6、实验结果分析
七、实验心得体会
实验三自编程序上机调试
一、实验目的
掌握用汇编语言编写程序的思路和方法。
二、实验内容
选作业题中题目上机调试。
三、程序框图
↓
N
N
Y
N
Y
四、程序清单
DSEG SEGMENT
ARY DW 4,9,2,8,6
N DW 5
DSEG ENDS
CSEG SEGMENT
ASSUME CS:CSEG,DS:DSEG
START: MOV AX,DSEG
MOV DS,AX
MOV CX,N
DEC CX
LOOP1: MOV DI,CX
MOV BX,0
LOOP2: MOV AX,ARY[BX]
CMP AX,ARY[BX+2]
JGE COTINUE
XCHG AX,ARY[BX+2]
MOV ARY[BX],AX
COTINUE:ADD BX, 2
LOOP LOOP2
MOV CX, DI
LOOP LOOP1
MOV AH, 4CH
INT 21H
CSEG ENDS
END START
五、实验结果
6、实验结果分析
7、实验心得与体会
实验四自编程序上机调试
一、实验目的
掌握用汇编语言编写程序的思路和方法。
二、实验内容
选作业题中题目上机调试。
三、程序流程图
四、程序清单
STACK SEGMENT STACK
DB 10 dup(?)
STACK ENDS
DATA SEGMENT
X DW 8326H
DATA ENDS
CODE SEGMENT
ASSUME CS: CODE, DS: DATA, SS:STACK
START: MOV AX, DATA
MOV DS, AX
MOV AX, X
AND AX, AX
JNS DONE
NEG AX
DONE: MOV X, AX
MOV AH, 4CH
INT 21H
CODE ENDS
END START
8、实验结果分析
9、实验心得与体会
实验五 8255并行I/O口实验
一、实验要求
利用8255可编程并行口芯片,实现输入/输出实验,实验中用8255PA口作输入,PB口作输出。
二、实验目的
1、了解8255芯片结构及编程方法。
2、了解8255输入/输出实验方法。
三、预备知识
8255是Intel公司生产的与Intel8080/8085系列的MPU配套的可编程外围接口电路,简称PPI。它有A、B、C三个八位端口寄存器,通过24位端口线与外部设备相连,基中C口可分为上半部和下半部。这24根端口线全部为双向三态。三个端口可分二组来使用,可分别工作于三种不同的工作方式。
四、实验原理图及连线
1、本实验主要用到的模块:8255模块、开关量输出模块、0-1指示模块、实验译码单元等;
2、PA0-PA7分别接开关量输出模块S0-S7对应的插座;
3、PB0-PB7分别接0-1指示模块DO71-DO78对应的插座;
4、8255A的片选/CS接地址译码单元的2A0-2A7;
5、数据线XD0—XD7接系统数据线区的任一插座。
图 3-3
五、实验内容
将实验的线路连接好后,编程,将8255的A口作为输入,输入信号由8个逻辑电平开关提供,B口作为输出,其内容由发光二极管来显示。
六、程序清单
L8255_CMD EQU 2A3H
L8255_PA EQU 2A0H
L8255_PB EQU 2A1H
L8255_PC EQU 2A2H
CODE SEGMENT
ASSUME CS:CODE,DS:CODE
BEGIN:
MOV CX,0FFH
AA: LOOP AA
MOV DX,L8255_CMD
MOV AL,9CH ;10011000
OUT DX,AL
NOP
NOP
NOP
NOP
NOP
BB: MOV DX,L8255_PA
IN AL,DX
XOR AL,0FFH
MOV DX,L8255_PB
OUT DX,AL
JMP BB
CODE ENDS
END BEGIN
七、程序框图
图 3-4
八、实验步骤
1、参照图中的内容连好线;
2、运行上位机软件,装载并运行相应程序即可(联机请参考程序8255.asm)。
注意:同学们自己编写程序时,8255的/CS连线可以接地址译码单元的其他信号,其它连线相同。如果用的端口与本实验不一样,也可以改变IO口的连线。
九、仪器配置ZY15MicInt12BB微机原理及接口实验箱 一台。
十、实验现象
当读到某个开关处于高电平时,对应的发光二极管就会亮
十一、思考题
根据程序列出实验中8255的各个端口的地址,如果8255的/CS改接译码信号280H,其它信号不变,那么对应的端口地址又是多少?
实验六 ADC0809A/D转换实验
一、实验目的
1、加深理解逐次逼近法模数转换器的特征和工作原理;
2、掌握A/D转换芯片与8088/86的接口方法;
3、了解A/D芯片ADC0809转换性能及编程方法。
二、预备知识
A/D转换器大致有三类:一是双积分A/D转换器,优点是精度高,抗干扰性好;价格便宜,但速度慢;二是逐次逼近A/D转换器,精度,速度,价格适中;三是并行A/D转换器,速度快,价格也昂贵。
实验用的ADC0809属第二类,是八位A/D转换器。每采集一次一般需100us。本程序是用延时查询方式读入A/D转换结果,也可以用中断方式读入结果,在中断方式下,A/D转换结束后会自动产生EOC信号,做为转换完成的信号。
三、实验原理说明及连线
1、本实验的位置在实验箱的“ADC0809模块”;
2、本实验用芯片ADC0809的片选地址为2B8H,实验箱上已固定好,不需要再连线;
3、将该实验模块的CLOCK和“信号源模块”的1MHz信号连接起来;
4、用排线将“系统数据总线输出单元”中的任意一组数据线和本实验模块的“ADC0809:XD0-XD7”连接起来;
5、将通道0模拟量输入端IN0接模拟信号产生电路模块中的电位器R093的中心抽头,然后将R093的两端一端接地,另一端接VCC(+5V)。
图 3-8
四、实验内容
利用电位器输出一个幅值可调的直流电压信号,送入ADC0809的通道0,将转换后的结果在屏幕上显示出来,并验证它与输入电压的关系。
五、实验步骤
1、确认连接好线路;
2、装载运行程序。
六、实验框图
图 3-9
七、仪器配置ZY15MicInt12BB微机原理及接口实验箱 一台
八、实验现象
当用户扭动电阻器时,屏幕将显示相应的数值。
九、思考题
按图中的连接线路,输入一个3V的模拟信号,输出的数字信号的理论值是多少,在实验箱上验证该值的正确性。
实验中用的ADC0809的IN0的地址是什么?
十、程序清单
CODE SEGMENT
ASSUME CS:CODE
START:
MOV DX,2B8H ;2B0H-2B7H
MOV AL,00H
OUT DX,AL
CALL DELAY
IN AL,DX
CALL SHOW
CALL DELAY
JMP START
SHOW PROC NEAR
PUSH DX
PUSH AX
MOV CL,4
SHR AL,CL
AND AL,0FH
CALL H2C
JC SHOW_OUT
MOV DX,88H
OUT DX,AL
POP AX
AND AL,0FH
CALL H2C
JC SHOW_OUT
MOV DX,88H
OUT DX,AL
MOV CX,0FFH
DELA:
LOOP DELA
SHOW_OUT:
POP DX
RET
SHOW ENDP
H2C PROC NEAR
CMP AL,0
JAE N0_9
JMP H2C_ERR
N0_9:
CMP AL,9
JBE N0_9_OK
CMP AL,0AH
JAE HEX_CMP
JMP H2C_ERR
HEX_CMP:
CMP AL,0FH
JBE HEX_CMP_OK
JMP H2C_ERR
HEX_CMP_OK:
CLC
ADD AL,37H
JMP CMP_OUT
N0_9_OK:
CLC
ADD AL,30H
JMP CMP_OUT
H2C_ERR:
STC
CMP_OUT:
RET
H2C ENDP
DELAY PROC NEAR
MOV CX,0FFH
DELEA:
LOOP DELEA
RET
DELAY ENDP
CODE ENDS
END START
实验报告的实验原理怎么写篇3
课程设计报告课题名称: C减语言编译器的词法分析器与语法分析器设计
提交文档学生姓名:
提交文档学生学号:
同组 成 员 名 单: 无
指导 教 师 姓 名: 张 斌
指导教师评阅成绩:
指导教师评阅意见:
提交报告时间: 年 月 日
课程设计目标学生在学习《编译原理》课程过程中,结合前5个章节的构造编译程序的词法扫描和语法分析的基本理论完成课程设计。要求实现一个小编译程序(包括符号表的构造,词法分析,语法分析),使学生将理论与实际应用结合起来。其中词法扫描输入为C- 语言的源程序(后缀名用.cm)文件,输出为C-语言的token序列,语法分析程序的输入为C-语言的源程序,输出为程序的语法树。语法树的表示主要通过各个结构token的缩进来表示出树的结构。
词法分析惯用词法
1.关键字:else if int return void while所有的关键字都是保留字,并且必须是小写。
2.专用符号:+ - * / < >= == != = ; , ( ) [ ] { } /* */
3.其他标记是ID和NUM,通过下列正则表达式定义:
ID=letter letter*
NUM=digit digit*
letter=a|..|z|A..|Z
digit=0|..|9
说明:C-语言区分大小写,ID表示标识符,由一个或多个字母组成,标识符只能包含字母中间不能有数字,NUM表示数字。
4.空格由空白、换行符和制表符组成。空格通常被忽略,出了它区分开ID、NUM关键字。
5.注释用通常的C语言符号/*...*/围起来。注释可以放在任何空白出现的位置(即注释不能放在标记内)上,且可以超过一行。注释不能嵌套。C-语言的注释与C语言的块注释相同。
算法描述
本程序算法通过以换行符为分割符将待分析的程序划分为各行。对于每行调用DealSymbol函数逐字分析,找到token,调用AddSpace函数将token前后插入空格,返回处理完后的程序行。
再将处理后的程序行字符串返回给Morphology函数(),函数将该字符串(即一行程序)以空格为分割符将待分析的程序行划分为各token(调用split方法分割可将多余的空格删去)。声明一个标记注释用的int型参数,并将其初始化为0(0表示不在注释中,1表示出于注释状态),随后逐词扫描。
当注释标记为0时,
扫描到"/*",注释标记赋值为1;
扫描到if,else,int,return,void,while输出"reserved word: " + 该token;
扫描到+ - * / < > = != = == ; , ( ) [ ] { } 直接输出 该token;
扫描到字母,则连续逐字扫描,直到扫描到非字母则返回"error",否则输出 "ID , name = " + 该token;
扫描到数字,则连续逐字扫描,直到扫描到非数字则返回"error",否则输出 "NUM , val = " + 该token;
当注释标记为1时,
直到扫描到"*/",注释标记赋值为0;
否则直接输出扫描到的项
核心源代码
private string AddSpace(string Tmp, int j, int l)
{
if (j > 0 && j < Tmp.Length - l)
{
Tmp = Tmp.Substring(0, j) + " " + Tmp.Substring(j, l) + " " + Tmp.Substring(j + l,
Tmp.Length - j - l);
}
else if (j == 0 && j < Tmp.Length - l)
{
Tmp = Tmp.Substring(j, l) + " " + Tmp.Substring(j + l, Tmp.Length - j - l);
}
else if (j > 0 && j == Tmp.Length - l)
{
Tmp = Tmp.Substring(0, j) + " " + Tmp.Substring(j, l);
}
return Tmp;
}
private string DealSymbol(string Tmp)
{
for (int j = 0; j < Tmp.Length; j++)
{
if (Tmp[j] == "+" || Tmp[j] == "-" || Tmp[j] == ";" || Tmp[j] == "," || Tmp[j] == "(" || Tmp[j] == ")" || Tmp[j] == "[" || Tmp[j] == "]" || Tmp[j] == "{" || Tmp[j] == "}")
{//加空格
Tmp = AddSpace(Tmp, j, 1);
j++;
}
else if (Tmp[j] == "" || Tmp[j] == "=" || Tmp[j] == "!")
{
if (j < Tmp.Length - 1)
{
if (Tmp[j + 1] == "=")
{
Tmp = AddSpace(Tmp, j, 2);
j += 2;
}
else
{
Tmp = AddSpace(Tmp, j, 1);
j ++;
}
}
}
else if (Tmp[j] == "*")
{
if (j < Tmp.Length - 1)
{
if (Tmp[j + 1] == "/")
{
Tmp = AddSpace(Tmp, j, 2);
j += 2;
}
else
{
Tmp = AddSpace(Tmp, j, 1);
j++;
}
}
}
else if (Tmp[j] == "/")
{
if (j < Tmp.Length - 1)
{
if (Tmp[j + 1] == "*")
{
Tmp = AddSpace(Tmp, j, 2);
j += 2;
}
else
{
Tmp = AddSpace(Tmp, j, 1);
j++;
}
}
}
}
return Tmp;
}
private void Morphology ()
{
int Remark = 0;
int i, j;
SourceCode.Text += "\r\n@";
string[] Line = SourceCode.Text.Split("\n");
i = 0;
while (Line[i] != "@") //逐行
{
Output.Text += (i + 1).ToString() + ": " + Line[i] + "\n";
Line[i] = Line[i].Replace("\r", " @");
Line[i] = Line[i].Trim();
Line[i] = DealSymbol(Line[i]);
string[] Tmp = Line[i].Split(" ");
j = 0;
i++;
while (Tmp[j] != "@") //逐字
{
if (Remark == 0 && Tmp[j] != "") //非注释ª
{
if (Tmp[j] != "/*")
{
Output.Text += " " + i.ToString() + ": "; //加行号
}
else
{
Remark = 1;
}
//保留字
if (Tmp[j] == "if" || Tmp[j] == "else" || Tmp[j] == "int" || Tmp[j] == "return" || Tmp[j] == "void" || Tmp[j] == "while")
{
Output.Text += "reserved word: " + Tmp[j] + "\r\n";
}
//专用符号
else if (Tmp[j] == "+" || Tmp[j] == "-" || Tmp[j] == "*" || Tmp[j] == "/" || Tmp[j] == "" || Tmp[j] == "=" || Tmp[j] == "!=" || Tmp[j] == "=" || Tmp[j] == "==" || Tmp[j] == ";" || Tmp[j] == "," || Tmp[j] == "(" || Tmp[j] == ")" || Tmp[j] == "[" || Tmp[j] == "]" || Tmp[j] == "{" || Tmp[j] == "}")
{
Output.Text += Tmp[j] + "\r\n";
}
//ID
else if ((Tmp[j][0] >= "a" && Tmp[j][0] = "A" && Tmp[j][0] = "a" && Tmp[j][k] = "A" && Tmp[j][k] = "0" && Tmp[j][0] = "0" && Tmp[j][k] declaration-list
2.declaration-list->declaration-list declaration | declaration
3.declaration -> var-declaration | fun-declaration
4.var-declaration -> type-specifier ID ; | type-specifier ID [NUM ]
5.type-specifier ->int | void
6.fun-declaration ->type-specifier ID ( params ) compound-stmt
7.params -> param-list | void
8.param-list ->param-list , param | param
9.param ->type-specifier ID | type-specifier ID [ ]
10.compound-stmt -> { local-declaration statement-list }
11.local-declarations -> local-declarations var-declaration | empty
12.statement-list -> statement-list statement | empty
13.statement ->expression | compound-stmt | selection-stmt | iteration-stmt | return-stmt
14.expression-stmt -> expression ; | ;
15.selection-stmt -> if ( expression ) statement | if ( expression ) statement
16.iteration-stmt -> while ( expression ) statement
17.return-stmt-> return ; | return expression ;
18.expression -> var = expression | simple-expression
19.var ->ID | ID [ expression ]
20.simple-expression -> additive-expression relop additive-expression | additive-expression
21.relop -> | >= | == | !=
22.additive-expression -> additive-expression addop term | term
23.addop -> + | -
24.term -> term mulop factor | factor
25.mulop -> * | /
26.factor -> ( expression ) | var | call | NUM
27.call -> ID ( args )
28.args -> arg-list | empty
29.arg-list -> arg-list , expression | expression
语法树结构表述
基本同属结构为:
语句的表述
if语句(选择语句):
while语句(循环语句)
output语句:
return语句:
word/media/image5.gif
复合语句:复合语句由“{”符号开始,后面跟着声明和语句列表作为其子节点(子节点之间为同属连接)
word/media/image6.gif
赋值表达式:(赋值表达式将赋值符号右边的表达式作为子节点,将赋值符号右边作为父节点)
word/media/image7.gif
算符表达式:
word/media/image8.gif
数组表达式:
word/media/image9.gif
算法描述
本程序算法总体思路是基于自底向上的分析进行语法树的构建。
第一步是调用之前写好的词法分析进行分析。将词法分析所得到的结果通过textbox保存,随后对每一行进行分析。
首先根据语法规则找到语句的first 集。再根据词法分析的结果进行逐词扫描,扫描到对应的先行词后,对随后可能出现的的token进行选择分析。把每一个独立的语句作为一个Point,语法树的构建可以在此基础上视作图的构建,即按Point之间的逻辑将其连接,再将Point的枝叶添加上去。例如:if (x>0),这条代码中的Point是if语句,Point的枝叶是表达式 ( x>0 )。
在扫描的过程中,建立一个嵌套栈和一个跟从集用于描述Point之间的逻辑关系。其中嵌套栈是用来保存嵌套的Point,即每一次进入新的一层嵌套之前。并保存下进入嵌套point的ID,且栈顶指针加1,每退出嵌套(”}” 或if | while 语句计数为0)栈顶指针减1。有嵌套栈顶始终保存当前嵌套下最新Point的ID。而跟从集则用于保存先当前Point跟从于哪一个Point后,体现在语句上是将跟从集[Point_ID] = 嵌套栈[栈顶],与嵌套栈配合则可以明确的表示出Point之间的层次关系。
对于程序中的表达式的分析采用中缀表达式的思想,对于所有运算符的优先级给予定义,并在ExpAnalysis()函数中进行分析,返回给PraseAnalysis()函数完成的表达式树的根节点。
最后根据跟从集将连接有枝叶的Point连接起来定义第一个Point为树的根节点,并显示则算法结束。
核心源代码
int Contr = 0;
private TreeNode ExpAnalysis(string[] str)
{
int i = 0, opPtr = 0, idPtr = 0;
TreeNode[] id = new TreeNode[100];
string[] op = new string[100];
if (str[i] == ";" || str[i] == "/" || str[i] == "*" || str[i] == "-" || str[i] == "+" || str[i] == "(" || str[i]
== ")" || str[i] == "==" || str[i] == "!=" || str[i] == ">=" || str[i] == "" || str[i] == "=")
{
op[opPtr++] = str[i];
int j = opPtr - 1;
if (j > 0)
{
while ((Priority (op[j])