版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第四章 汇编语言程序设计,4. 1 汇编语言的基础语法 4. 2 汇编语言程序设计,4.1 汇编语言的基本语法 4.1.1 汇编语言程序的格式 4.1.2 常量、标识符和表达式 4.1.3 指示性语句 4.1.4 指令性语句 4.1.5 宏指令,教学内容(2学时) 汇编语言的语句格式、汇编语言的运算符、表达式 汇编语言源程序的结构 汇编语言程序汇编步骤 教学目标 掌握汇编程序的基本格式 常用运算符的使用方法,汇编的步骤 教学重点及难点 汇编程序的基本格式 正常返回DOS操作系统的处理 常用运算符(如取值、属性)的使用方法。,4.1.1 汇编语言程序的格式 例:功能:求10个字节数据a1a10之
2、和。 (P123) DATA SEGMENT AT 2000H ARRAY DB a1,a2,a3,a10 Count EQU $-ARRAY SUM DW ? DATA ENDS STACK SEGMENT PARA STACK STACK STAK DB 10 DUP(?) TOP EQU LENGTH STAK STACK ENDS CODE SEGMENT ASSUME CS:CODE,DS:DATA,SS:STACK START: MOV AX,DATA MOV DS,AX MOV AX,0 MOV DI,OFFSET SUM MOV BX,OFFSET ARRAY MOV CX,C
3、OUNT LOP: ADD AL,BX ADC AH,0 INC BX LOOP LOP MOV DI,AX MOV AH,4CH INT 21H CODE ENDS END START,8088汇编语言的源程序是由多个段组成的, 一个可执行的汇编程序一般至少有一个代码段,其中包含可执行的语句。其基本格式如右所示。其特点如下: 1)分段结构 指令性语句 2)使用 语句行 指示性语句 3)必须使用ASSUME语句完成段的指认 4)必须完成段地址寄存器及相关寄存器的初始化。 a)用户初始化:DS、ES b)系统初始化:CS:IP、SS:SP 5)有保证正常返回DOS的处理。,基本格式和特点,S_N
4、AME1 SEGMENT 语句 语句 S_NAME1 ENDS S_NAME2 SEGMENT 语句 语句 S_NAME2 ENDS S_NAME3 SEGMENT 语句 语句 S_NAME3 ENDS END 标号,每个段是由语句行构成的。一个语句行的基本格式为: a)指令性语句: 标号 : 操作码 操作数1 ,操作数2 ;注释 例:LP: add al,bx b)指示性语句 名字/变量 命令 参数表 ;注释 例:data segment at 2000h,1. 标识符 标识符由一串字符构成,用于一段程序、一组(或一个)数据或一个段的开头。 2. 保留字 保留字是汇编语言中预先保留的特殊字串
5、,只能用于特殊用途,所有8086/8088的指令、伪指令和寄存器名都是保留字。如AX、MOV、DB、INT、EQU等等。 保留字不能用作标识符 3. 界符 界符是用于一个程序或一条指令中不同部分的分隔符,如MOV AX, 0010H中的“,”就是界符。 8086/8088汇编语言的界符 ; * , : + - = ( ) $ MOV DS,AX MOV SI,OFFSET BUF1 MOV CX,LENGTH BUF2 MOV BL,SIZE BUF3 MOV AL,BUF1 MOV AH,BUF1+2, 综合运算符 综合运算符包括两个地址操作符 PTR、THIS和LABEL。 格式: 类型
6、PTR exp;类型允许WORD、BYTE、DWORD、NEAR、FAR PTR改变存储器地址操作数的操作类型,但其段地址和偏移地址不变。 例1:重新指定类型: DATA1 DW 1234H,5678H,34 12 78 56,DS,MOV AL, DATA1 MOV AL, BYTE PTR DATA1 ;(AL)=34H MOV AX,DATA1;(AX)=1234H 例2:指定操作数的类型 INC BX ;操作数类型不明确 改为: INC BYTE PTR BX INC WORD PTR BX 例3:重新定义一个新变量 DATA1 DW 1234H,5678H BDATA1 EQU BY
7、TE PTR DATA1,DATA1,BDATA1,DATA1 SEGMENT WBUFFER EQU THIS WORD 两语句必须相邻, BUFFER DB 12H, 34H, 00H, 91H 且THIS必须在前 DATA1 ENDS CODE1 SEGMENT ASSUME CS: CODE1, DS: DATA1 START: MOV AX, DATA1 MOV DS, AX MOV AL, BUFFER MOV BX, WBUFFER CODE1 ENDS END START,THIS用来建立新的存储器地址操作数,且不分配存储单元。新的操作 数类型在THIS中指定,而其段地址和偏移
8、量就是汇编时的当前值。 格式: THIS 类型,12 34 00 91 85,DS,BUFFER,WBUFFER,AL=12H BX=3412H,LABEL用来定义其语句中的变量(标号)的类型属性为语句中设定的 类型,此时变量(或标号)的段属性和偏移地址属性由该语句 的位置确定。 格式: 标号/变量 LABEL 类型 例:BUFB LABEL BYTE 两语句必须相邻, BUFW DW 1234H,5678H 且LABEL语句必须在前 MOV AX,BUFW; (AX)=1234H MOV AL, BUFB; (AL)=34H,小结 、在使用或访问变量时,必须指定变量的类型属性,即源操作数与目
9、的操作数的类型属性一致,操作合法。 、可以有多种方法指定、改变变量的类型属性: PTR可在访问时指定变量属性 THIS,LABEL在变量定义时,指定变量属性,教学内容(2学时) 伪指令 定义数据伪指令、符号定义伪指令、段定义伪指令、设定段寄存器伪指令、 定义过程的伪指令、 ORG、END伪指令 宏 教学目标 要求学生了解伪指令的功能,掌握定义数据,定义符号、段定义、过程定义 指令的使用方法 能编写格式正确的汇编程序 教学重点及难点 定义数据,定义符号、段定义、过程定义、设定段寄存器、定位 汇编结束和开始,4.1.3 指示性语句(伪指令) 在8086/8088汇编语言中伪指令是用于诸如数据定义、
10、存储区分配等功能。所谓伪指令是非机器指令,它是在汇编期间进行操作的。,一、 程序开始和结束语句 在程序的开始可以用 NAME 或 TITLE 为程序取名字。 格式为: NAME 程序名 TITLE 程序名 整个程序的结束使用 END 标出,当汇编器读到 END 时,它认为程序到此就结束了。在程序中,首条被执行的语句有一个标号,在程序的结尾使用 END 后跟上这个标号,用以标出这个程序的开始执行处。 注: NAME 、TITLE 操作不是必须的。 END 则必不可少。,二、段的定义 分段结构是8086/8088的特点,程序和存储器都是按段来组织的,语句有:SEGMENT、ENDS、ASSUME、
11、ORG。 1. 段定义语句 在段定义中,SEGMENT和ENDS总是成对使用的,它们将数据和程序分为多个段,如数据段、栈段和代码段。 2. 命令ORG、ASSUME ASSUME语句紧跟在SEGMENT语句之后,是汇编时进行操作的,它用于在汇编时告诉汇编器,哪个是数据段,哪个是代码段,哪个是堆栈段。 ORG用于指定目标程序存放单元的起始偏移地址,通常写在第一条源程序的前面,用于指定这段程序的首地址。如使用了: ORG 1000H MOV AL,BL 则程序执行时就从CS:1000H处开始执行其后面的程序。(MOV指令所在的内存单元在本段的偏移地址为1000H。,Segname segment
12、align_type ;定位类型 combine_type ;组合类型 class ;类别 定位类型: para:指定段的起始地址必须从小节边界开始,即段地址的最后1位(十六进制)必须为0 。 byte: 该段可以从任何地址开始。 word:该段必须从字的边界开始,即段地址必须是偶数。 page:该段必须从页的边界开始,即段地址的最后2位(十六进制)必须为0 。 组合类型: public:该段连接时将与有相同名字的其它段连接在一起。 common:该段在连接时与其它同名分段有相同的起始地址(会产生覆盖)。 at expression :使段的起始地址是表达式所指定的16位段地址,但不能指定代码
13、段。 stack:指定该段在运行时为堆栈段的一部分。 类别: 连接时用于组成段组的名字。,Segment 的类型及属性说明在需要用连接程序将本程序与其它模块相连接时,需要使用这些说明。,注意: SEGMENT和ENDS前面必须有标号,而且在相互配对的段,它们前面要使用相同的标号。对于不同的段定义标号,尽管这些标号可以是任意字串,但为了程序的可读性,应使其有一定的意义。 ASSUME语句可使汇编器知道CS、DS、SS指向哪个段,但它只在汇编时起作用,在运行时CPU并不知道除CS外的其它段地址,所以必须在程序中用指令进行赋值。 首条被执行的语句有一个标号,在程序的结尾使用END后跟上这个标号,用以
14、标出这个程序的开始执行处。(只需在主程序的结束语句中写出标号,其他主程序模块的结束语句只需要写出语句END即可。),三、 过程定义语句 和其它程序设计一样,8086/8088汇编程序设计有过程或子程序的设计方法。8086/8066汇编程序的过程从运行位置上分为近过程(NEAR)和远过程(FAR),缺省值为NEAR。其定义如下: PROC_NAME1 PROC NEAR RET PROC_NAME1 ENDP PROC_NAME2 PROC FAR RET PROC_NAME2 ENDP,过程和其它程序可定义在同一个段中,也可定义在不同的段中。对过程的调用要使用CALL语句,如: CALL PR
15、OC_NAME1 CALL PROC_NAME2 如果在过程定义中没有写明是NEAR过程或FAR过程,则汇编器将这个过程默认为NEAR过程。,四、 符号定义语句 EQU 为了使程序便于阅读和修改,我们有时使用一个符号来代表一个值,而符号代表了一定的意义,在程序中使用一个符号代表一个值进行操作,其格式为: 名字 EQU 表达式 例如: PORT EQU 3F8H 在程序中可使用 MOV DX, PORT 对DX进行赋值,实际上PORT就是一个常量。 例:DATA SEGMENT (P135,例4-11) ARRAY DB 10H,24H,5AH,0C7H,98H,ABCDE COUNT EQU
16、$ - ARRAY ;$-ARRAY=000AH-0000H=10 MAX DB ? DATA ENDS,还可在语句中进行运算,如: DATA_PORT EQU 3F8H STAT_PORT EQU 3F8H+2 SEED EQU 10 FUNC EQU SEED*SEED+2*SEED+1 = 号操作 对符号的赋值还可使用“=”操作,它与EQU的区别是“=”操作可以重复定义,而EQU则不能重复定义。如: X=3 Y=6 Y=Y*Y-X MOV AX, Y 通过上述操作,最后使Y=33,后面的MOV语句中,当生成目标代码时将用33取代Y。即 MOV AX, 21H (33D),五、 数据定义语
17、句 数据定义语句用于为数据分配相应的存储单元。用一个符号名代表一个或一些单元,并可为这个或这些单元提供初始值。定义数据的操作符有: 字节定义DB 字定义DW 双字定义DD 四字定义DQ 十字节定义DT 重复定义 m DUP(n)_ (重复m次个数据 n ) 与数据相联系的符号名称为变量。 数据定义语句的格式为: 变量名 操作符 数据项,通过上述定义,在存储器中将产生如图所示的结果,以DATA1到DATA5为例: 例: DATA1 DB ? DATA2 DW 1000H DATA3 DD 3000A455H DATA4 DB 4 DUP(0) DATA5 DW 0120H, 0240H, 036
18、0H DATA6 DB 2 DUP(12H,34H,56H),DS,随机 00 10 55 A4 00 30 00 00 00 00 20 01 40 02 60 03 12 34 56 12 34 56,DATA1 DATA2,DATA3,DATA4,DATA5,DATA6,DS,54 48 49 53 42 41 44 43 43 00 42 41 00 00,例: DATA7 DB THIS;同DATA7 DB T,H,I,S DATA8 DW AB,CD ,C DATA9 DD AB,DATA7,T H I S,注意: 1. 数据定义语句在存储器中占有相应的 单元,如上面语句中的第二句
19、在程序 运行时将会以00和10占据两中存储单元。 而EQU只是定义了一个数据,在汇编 后以实际数据的形式体现在程序中。 也就是说,EQU语句不会占有存储单元。 2. EQU可以用在指令中,而数据定义语句 不可以。,DATA8,DATA9,4.1.4 指令性语句 标号 : 操作码 操作数1 ,操作数2 ;注释 一、标号 段属性 偏移地址属性 类型属性(NEAR、FAR) SEG 标号 OFFSET 标号 TYPE 标号 例:程序中有标号ME(NEAR类型)。若想定义新变量KI,类型为FAR, 而两者的段地址、偏移地址属性相同。 这样段内转移用ME,段间转移用KI,两个标号表示的是同一地址。 1)
20、 用PTR重新指定类型 段内调用:JMP ME 段间调用:JMP FAR PTR ME 2)用EQU和PTR定义新标号 ME:MOV AX,BX KI EQU FAR PTR ME 3)用EQU和THIS定义新标号 KI EQU THIS FAR ME:MOV AX,BX 4)用LABEL定义新标号 KI LABEL FAR ME:MOV AX,BX,4.1.5 宏指令 宏指令:程序员用汇编语言编程是,对于程序中多次重复使用的指令序列可定义一条宏指令,编写程序时就用这条宏指令代替该指令序列,从而简化书写工作。 一、宏定义、宏名字、宏调用和宏展开 宏定义:宏名字 MACRO 形式参数 ENDM
21、宏调用:宏名字 实参数,例1:无形参的宏指令 宏定义:SAV MACRO PUSH AX PUSH BX PUSH CX ENDM 宏调用:程序 SAV 宏展开:程序 PUSH AX PUSH BX PUSH CX ,例2:带参宏指令 宏定义:MU MACRO OPR1,OPR2,RESULT PUSH AX MOV AL,OPR1 IMUL OPR2 MOV RESULT,AX POP AX ENDM 宏调用:程序 MU CL,VAR,XYZBX 宏展开:程序 PUSH AX MOV AL,CL IMUL VAR MOV XYZBX,AX POP AX ,二、宏指令与子程序的区别 )子程序目
22、标程序比宏调用短。 在汇编时,汇编程序将宏指令的宏体代码展开嵌入到程序中的宏调用处,然后转换成机器码生成目标程序。因此,宏指令只简化了源程序,但并没有简化目标程序;而子程序(过程)通过CALL指令调用,执行子程序时处理器改变CS:IP使其转子程序处执行,通过RET指令返回主程序,子程序的调用可以简化目标程序. )宏指令的执行速度比子程序快. 子程序每次调用和返回都要增加额外开销,而宏调用不会。,教学内容(2学时) 指令系统综合应用 顺序、分支程序分析与设计方法 常用例行程序设计实例 汇编语言源程序的调试方法 教学目标 掌握指令系统的应用方法 能完成顺序、分支程序分析与设计 理解常用的程序设计实
23、例 分支程序设计与分析中汇点的处理方法 教学重点及难点 常用的程序设计实例(重点) 分支程序设计与分析中汇点的处理方法(难点),汇编语言程序的执行过程:,编辑程序,. ASM 文件,汇编程序,. OBJ 文件,连接程序,. EXE 文件,Edit 等,MASM,LINK,4.2 汇编语言程序设计 4.2.1 概述 4.2.2 程序的基本结构 4.2.3 DOS、BIOS功能调用,4.2.1 概述 汇编语言程序设计与其它语言的程序设计一样,都要有良好的数据结构和算法,对每个要解决的问题要经过入下步骤: 分析课题:根据问题提出相应的算法或逻辑过程; 根据已确定的算法或逻辑过程画出程序流程图,把解题
24、的思路和逻辑 顺序以图示的方法表示出来。 分配工作单元和寄存器。当然,在8086/8088汇编程序设计中,由于可 用资源相对其它一些CPU和计算机系统较多,所以这项工作也可在程 序编制中进行。 编写程序代码。 上机调试程序,在程序设计中,程序的效率是程序设计好坏的重要指标,特别是在汇编程序设计中,其特点要求我们对程序运行的效率加以重点关注。对于汇编语言程序我们可以考虑以下几方面作为程序运行效率的衡量标准: 程序的执行时间。每一条语句都有自己的执行时间,在8086/8088指令 手册中每条指令的运行时间都有明确的定义。根据这些时间,我们可 算出程序的运行时间。 程序所占有的字节数。有一些计算机系
25、统,可能应用于工业控制或工 业过程检测,不需要过多的硬件资源,比如存储单元,所以就要求我 们的程序有尽可能少的字节数,以满足缩减硬件资源的要求。 程序的语句行数。,4.2.2 程序的基本结构 顺序结构、分支结构、循环结构和子程序结构。 一、顺序结构,例1:将ASCII码表示的两位十进制数转换成一字节二进制数。 算法:37H,39H0000,0111B*10+0000,1001B 0100,1111B(4FH,79),(P162 例4-29),二、 分支程序 在很多实际问题中,通常要根据不同的情况,执行不同的程序块或语句,这就需要在设计程序时使用运算后的结果,依据一定的条件进行相应的判断,根据判
26、断结果的真或假,去运行相应的程序或语句。,X=0,X0,Y=0,Y=1,Y= -1,Y,Y,N,N,例1 :有一符号函数如下: 1 x0 y=f(x)= 0 x=0 -1 x0 要求写出程序完成上述计算。,框图如下,开始,汇点,DATA SEGMENT X DB ? Y DB ? DATA ENDS CODE SEGMENT ASSUME CS:CODE, DS:DATA START: MOV AX, DATA MOV DS, AX MOV AL, X OR AL, AL JE ZERO JNS PLUS MOV BL, -1 JMP HALT ZERO: MOV BL, 0 JMP HALT
27、 PLUS: MOV BL, 1 HALT: MOV Y,BL MOV AH, 4CH INT 21H CODE ENDS END START,在上面的程序中,要特别注意其中的两中JMP HALT的使用,从而保证每个分支的完整性。,例2 :数据块的传送。 要求把内存中某一区域的源数据块传送到另一区域。编程时,必须判断源数据区同目的数据区之间有无重叠,以决定采用增量传送还是减量传送。(P149 例4-19) 例3:利用跳转表实现分支。 在内存的一个连续区中,连续存放一系列跳转地址、跳转指令或关键字,组成一个决定程序分支的跳转表。 某工厂有8种产品的加工程序R0到R7分别存放在以SBR0、SBR7
28、为首地址的内存区域中这8个首地址的偏移地址连续存放在以BASE为首地址的跳转表中,编程实现根据产品编号自动该产品的加工程序。(P150例4-20),DATA SEGMENT BASE DW SBR0,SBR1,SBR2,SBR3 DW SBR4,SBR5,SBR6,SBR7 BN DB ? DATA ENDS COSEG SEGMENT ASSUME CS:COSEG,DS:DATA START PROC FAR BEGIN PUSH DS MOV AX,0 PUSH AX MOV AX,DATA MOV DS,AX MOV AL,BN MOV AH,0 ADD AL,AL MOV BX,OF
29、FSET BASE ADD BX,AX MOV AX,BX JMP AX RET START ENDP COSEG ENDS END BEGIN,;根据跳转表 MOV AL,BN MOV BL, AL MOV AL,AL ADD AL,BL MOV AH,0 MOV BX,OFFSET BASE ADD BX,AX JMP AX,(P150例4-20),(P152例4-21),教学内容(2学时) 转移类及应用 循环程序设计、子程序设计 递归程序设计和分析方法 排序程序的设计、有序查找程序设计实例 教学目标 掌握转移类指令的应用方法 能阅读利用堆栈操作传递参数的子程序 能完成过程调用程序编写 理
30、解常用的程序设计实例 了解多重循环程序设计方法 教学重点及难点 常用的程序设计实例 循环程序的设计方法(重、难点),三、 循环程序 对于程序中多次、有规律执行的部分,我们通常使用循环结构要重复运行这些部分,使程序有较高的运行效率和可读性。循环结构主要由三部分组成,它们是: 1. 循环体:重复运行的部分,其中还包含了工作部分和循环控制部分。工作部分进行相应的操作,而循环控制部分则保证在不满足循环条件时,跳出循环。 2. 循环结束条件:在循环体中包括了循环结束条件运算部分。每循环一次除了工作部分进行相应的操作外,循环条件部分还要通过运算,得出当前循环的状态,以便在适当的条件下结束循环。 3. 循环
31、初值:用于设置开始循环时,循环体所处的初始状态,如循环变量初值,循环体中用到的数据和地址指针等。,累加求和:1)符号数/无符号数; 2)和没有超出/超出一个原始数据表示的范围 例1:求10个字节符号数之和 s 。允许|s|127. BUFF DB -1,34,23,-23,9,4,2,-28,124,45 N EQU $-BUFF RESULT DW ? XOR BX , BX ; 和清0 MOV CX , N LEA SI , BUFF NEXT: MOV AL , SI CBW ADD BX , AX INC SI LOOP NEXT MOV RESULT , BX HLT,例3:编制完成
32、两个4字节的BCD码的加法运算程序。,例2:将BUF区的数组中的元素的绝对值送到RES区中,同时统计负数元素的个数,(P167 例4-34),(参见P155 例4-23),例4:在内存某一缓冲区中,存 放着若干用BCD码表示的十 进制数,每一个单元中存放 两位,要求将它们转换成 ASC码,存放在缓冲区, 高4位的BCD码转换的 ASC码放在地址较高的单 元。(BCDASC.ASM),BCDBUF ASCBUF,65 23 02 00 24 35 36 33 32 32 30,流程图,开始,设地址,设转换个数,转换低 4 位,取数,存结果,转换高 4 位,存结果,CX -1CX,CX=0?,结束
33、,MOV SI, Offset BCDBUF MOV DI, Offset ASC BUF MOV CH, Count Again: MOV AL, SI ;取BCD码数 INC SI MOV BL, AL ;暂存,用于高位转换 AND AL, 0FH OR AL, 30H ;转换低位 MOV DI, AL ;存低位ASC码 INC DI MOV AL, BL ; 0 1 1 0, 0 1 0 1 MOV CL, 4 SHR AL, CL ; 0 0 0 0, 0 1 1 0 OR AL, 30H ; 0 0 1 1, 0 1 1 0 MOV DI, AL ;转换高位 INC DI DEC CH JNZ Again HLT,BCDBUF ASCBUF,65 23 02 00 24 35 36 33 32 32 30,0 1 1 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 1 1 1 1 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0 1 1 0 1 0 1,SI,DI,在子程序设计中 要明确地定义出这个子程序的入口参数和出口参数,使调用者能方便地使
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 机器设备安全培训心得课件
- 安全培训警句大全课件
- 医患关系融洽的描述技巧
- 单位消防安全检查汇报模板
- 安全培训要点记录内容课件
- 冬季服装销售话术
- 哺乳期护理与管理实践
- 心电图护理急救处理视频
- 儿科湿疹的家长心理支持
- 消防安全条幅pdf下载
- 云南师大附中2026届高三高考适应性月考卷(六)思想政治试卷(含答案及解析)
- 建筑安全风险辨识与防范措施
- CNG天然气加气站反恐应急处置预案
- 培训教师合同范本
- 2026年黑龙江单招职业技能案例分析专项含答案健康养老智慧服务
- 2025宁夏贺兰工业园区管委会招聘40人模拟笔试试题及答案解析
- (2025)70周岁以上老年人换长久驾照三力测试题库(附答案)
- 医院外科主任职责说明书
- 建设单位项目安全生产保证体系
- 2026期末家长会:初三备战没有不辛苦的 教学课件
- 真空乳化设备维护与清洁操作手册
评论
0/150
提交评论