导航:首页 > 源码编译 > 编译原理exp

编译原理exp

发布时间:2023-01-08 00:19:16

1. 有人知道编译原理实验之词法分析器用C++怎么做吗

#include "globals.h"
#include "util.h"
#include "scan.h"
#include "parse.h"

static TokenType token; /* holds current token */

/* function prototypes for recursive calls */
static TreeNode * stmt_sequence(void);
static TreeNode * statement(void);
static TreeNode * if_stmt(void);
static TreeNode * repeat_stmt(void);
static TreeNode * assign_stmt(void);
static TreeNode * read_stmt(void);
static TreeNode * write_stmt(void);
static TreeNode * exp(void);
static TreeNode * simple_exp(void);
static TreeNode * term(void);
static TreeNode * factor(void);

static void syntaxError(char * message)
{ fprintf(listing,"\n>>> ");
fprintf(listing,"Syntax error at line %d: %s",lineno,message);
Error = TRUE;
}

static void match(TokenType expected)
{ if (token == expected) token = getToken();
else {
syntaxError("unexpected token -> ");
printToken(token,tokenString);
fprintf(listing," ");
}
}

TreeNode * stmt_sequence(void)
{ TreeNode * t = statement();
TreeNode * p = t;
while ((token!=ENDFILE) && (token!=END) &&
(token!=ELSE) && (token!=UNTIL))
{ TreeNode * q;
match(SEMI);
q = statement();
if (q!=NULL) {
if (t==NULL) t = p = q;
else /* now p cannot be NULL either */
{ p->sibling = q;
p = q;
}
}
}
return t;
}

TreeNode * statement(void)
{ TreeNode * t = NULL;
switch (token) {
case IF : t = if_stmt(); break;
case REPEAT : t = repeat_stmt(); break;
case ID : t = assign_stmt(); break;
case READ : t = read_stmt(); break;
case WRITE : t = write_stmt(); break;
default : syntaxError("unexpected token -> ");
printToken(token,tokenString);
token = getToken();
break;
} /* end case */
return t;
}

TreeNode * if_stmt(void)
{ TreeNode * t = newStmtNode(IfK);
match(IF);
if (t!=NULL) t->child[0] = exp();
match(THEN);
if (t!=NULL) t->child[1] = stmt_sequence();
if (token==ELSE) {
match(ELSE);
if (t!=NULL) t->child[2] = stmt_sequence();
}
match(END);
return t;
}

TreeNode * repeat_stmt(void)
{ TreeNode * t = newStmtNode(RepeatK);
match(REPEAT);
if (t!=NULL) t->child[0] = stmt_sequence();
match(UNTIL);
if (t!=NULL) t->child[1] = exp();
return t;
}

TreeNode * assign_stmt(void)
{ TreeNode * t = newStmtNode(AssignK);
if ((t!=NULL) && (token==ID))
t->attr.name = String(tokenString);
match(ID);
match(ASSIGN);
if (t!=NULL) t->child[0] = exp();
return t;
}

TreeNode * read_stmt(void)
{ TreeNode * t = newStmtNode(ReadK);
match(READ);
if ((t!=NULL) && (token==ID))
t->attr.name = String(tokenString);
match(ID);
return t;
}

TreeNode * write_stmt(void)
{ TreeNode * t = newStmtNode(WriteK);
match(WRITE);
if (t!=NULL) t->child[0] = exp();
return t;
}

TreeNode * exp(void)
{ TreeNode * t = simple_exp();
if ((token==LT)||(token==EQ)) {
TreeNode * p = newExpNode(OpK);
if (p!=NULL) {
p->child[0] = t;
p->attr.op = token;
t = p;
}
match(token);
if (t!=NULL)
t->child[1] = simple_exp();
}
return t;
}

TreeNode * simple_exp(void)
{ TreeNode * t = term();
while ((token==PLUS)||(token==MINUS))
{ TreeNode * p = newExpNode(OpK);
if (p!=NULL) {
p->child[0] = t;
p->attr.op = token;
t = p;
match(token);
t->child[1] = term();
}
}
return t;
}

TreeNode * term(void)
{ TreeNode * t = factor();
while ((token==TIMES)||(token==OVER))
{ TreeNode * p = newExpNode(OpK);
if (p!=NULL) {
p->child[0] = t;
p->attr.op = token;
t = p;
match(token);
p->child[1] = factor();
}
}
return t;
}

TreeNode * factor(void)
{ TreeNode * t = NULL;
switch (token) {
case NUM :
t = newExpNode(ConstK);
if ((t!=NULL) && (token==NUM))
t->attr.val = atoi(tokenString);
match(NUM);
break;
case ID :
t = newExpNode(IdK);
if ((t!=NULL) && (token==ID))
t->attr.name = String(tokenString);
match(ID);
break;
case LPAREN :
match(LPAREN);
t = exp();
match(RPAREN);
break;
default:
syntaxError("unexpected token -> ");
printToken(token,tokenString);
token = getToken();
break;
}
return t;
}

/****************************************/
/* the primary function of the parser */
/****************************************/
/* Function parse returns the newly
* constructed syntax tree
*/
TreeNode * parse(void)
{ TreeNode * t;
token = getToken();
t = stmt_sequence();
if (token!=ENDFILE)
syntaxError("Code ends before file\n");
return t;
}
上面是一个语法分析器的主代码部分它可以识别类似下面的代码,但是由于篇幅有限,上面的代码不是完整代码,完整代码太长,还有好几个文件。
read x; { input an integer }
if 0 < x then { don't compute if x <= 0 }
fact := 1;
repeat
fact := fact * x;
x := x - 1
until x = 0;
write fact { output factorial of x }
end

2. C++:算术表达式求值

1/(1+1/(1+1/(x+y)));
x*(x*(x*(a*x+b)+c)+d)+e;
log(1+pow(fabs((a+b)/(a-b)),10));
sqrt(1+pi/2*cos(48));
1/tan((1-x*x)/(1+x*x));
//由于c语言中没提供cot函数,所以就用tan的倒数表示了。
log10(a*a+a*b+b*b);

3. 编译原理考试问题:已知表达式文法G(Exp)

简单起见,用E代表Exp,用T代表Term,用F代表Factor。下面是所求属性文法

(1)E→ E1 + T E.val:=E1.val+T.val /* 为了区别→两侧的E, →右侧的E用E1表示 */

(2)E→
T E.val:=T.val

(3)T→ T1 * F T.val:=T1.val*F.val

(4)T→
F T.val:=F.val

(5)F→(E) F.val:=E.val

(6)F→num F.val:=num.val

4. 正则表达式

正则经常用于js 判断手机号,邮箱等,通过简单的办法来实现强大的功能

符号解释

字符 描述
\ 将下一个字符标记为一个特殊字符、或一个原义字符、或一个 向后引用、或一个八进制转义符。例如,'n' 匹配字符 "n"。'\n' 匹配一个换行符。序列 '\\' 匹配 "\" 而 "\(" 则匹配 "("。
^ 匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 '\n' 或 '\r' 之后的位置。
$ 匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 '\n' 或 '\r' 之前的位置。
* 匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。* 等价于{0,}。
+ 匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。
? 匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等价于 {0,1}。
{n} n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。
{n,} n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。
{n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。
? 当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 "oooo",'o+?' 将匹配单个 "o",而 'o+' 将匹配所有 'o'。
. 匹配除 "\n" 之外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用象 '[.\n]' 的模式。
x|y 匹配 x 或 y。例如,'z|food' 能匹配 "z" 或 "food"。'(z|f)ood' 则匹配 "zood" 或 "food"。
[xyz] 字符集合。匹配所包含的任意一个字符。例如, '[abc]' 可以匹配 "plain" 中的 'a'。
[^xyz] 负值字符集合。匹配未包含的任意字符。例如, '[^abc]' 可以匹配 "plain" 中的'p'。
[a-z] 字符范围。匹配指定范围内的任意字符。例如,'[a-z]' 可以匹配 'a' 到 'z' 范围内的任意小写字母字符。
[^a-z] 负值字符范围。匹配任何不在指定范围内的任意字符。例如,'[^a-z]' 可以匹配任何不在 'a' 到 'z' 范围内的任意字符。
\d 匹配一个数字字符。等价于 [0-9]。
\D 匹配一个非数字字符。等价于 [^0-9]。
\f 匹配一个换页符。等价于 \x0c 和 \cL。
\n 匹配一个换行符。等价于 \x0a 和 \cJ。
\r 匹配一个回车符。等价于 \x0d 和 \cM。
\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
\S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\t 匹配一个制表符。等价于 \x09 和 \cI。
\v 匹配一个垂直制表符。等价于 \x0b 和 \cK。
\w 匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。
\W 匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。

具体怎么使用还得多看例子,对照解释

5. 这个用C语言写的计算器的思路是什么

对初学编程者来说,这个程序的原理确实难了点,因为它用到了编译原理的知识.
即如果设一个四则运算表达式的形式为S,那么它一定是一个以等号结尾的运算式,即S->exp=,->是推导符号.
运算式exp又可以继续推导成
exp->exp+term|exp-term|term
exp表示加减运算,term表示乘除运算.这个推导式反映了乘除的优先级比加减高.
即要先计算乘除式的结果,再来加减.
term可以推导如下:
term->term*factor|term/factor|factor
factor->num|(E)
factor是数字或者一个被括号括住的运算式,表示最高优先级.
数字本身是不带运算的,是原子性的,肯定是最高优先级.
括号是被规定了优先计算.
这个程序的代码就是按照上面的推导式,用递归方式来分析运算式的.

6. 计算器的实现(C语言)

这个计算器是卖不出去的,因为功能过于简单o(∩_∩)o...
不支持多目运算,进制转换只能将十进制整数转换为其他进制整数,还有很多地方可以改进的,由于时间关系就没一一写出来了。
#include<stdio.h>
void add(void);
void sub(void);
void mul(void);
void div(void);
void sc(void);
void er(void);

int main()
{
int ch;
while(1)
{
printf("\n[Caculator]\n1.+ 2.- 3.* 4./ 5.Size Change 6.Exchange Rate 7.Quit\n");
do{
printf("Input Your Chooice:");
scanf("%d", &ch);
}while(!(ch > 0 && ch < 8));
if(ch == 7)
break;
switch(ch)
{
case 1:
add();
break;
case 2:
sub();
break;
case 3:
mul();
break;
case 4:
div();
break;
case 5:
sc();
break;
case 6:
er();
break;
default:
break;
}
}

return 0;

}

void add()
{
float a,b;
printf("[add]:Input a and b:");
scanf("%f%f",&a,&b);
printf("[add]Answer:%f\n",a+b);
}

void sub()
{
float a,b;
printf("[sub]:Input a and b:");
scanf("%f%f",&a,&b);
printf("[sub]Answer:%f\n",a-b);
}

void mul()
{
float a,b;
printf("[mul]:Input a and b:");
scanf("%f%f",&a,&b);
printf("[mul]Answer:%f\n",a*b);
}

void div()
{
float a,b;
printf("[div]:Input a and b:");
scanf("%f%f",&a,&b);
printf("[div]Answer:%f\n",a/b);
}

void sc()
{
int a,b,i;
char c[100];
printf("[Size Change]Input the number and change size:");
scanf("%d%d",&a,&b);
for(i = 0;a/b != 0; i++)
{
c[i] = a%b;
a /= b;
}
c[i] = a%b;
printf("[Size Change]:");
for(;i >= 0;i--)
{
printf("%d\n", c[i]);
}
}

void er()
{
float a,b;
printf("[Exchange Rate]:Input the money and rate:");
scanf("%f%f",&a,&b);
printf("[Exchange Rate]:%f\n", a*b);
}

7. 求一个用C++编过计算器的,就是那种加减乘除三角函数可以写一排算的

//*************************************
//数学表达式解析类
//*************************************
//Expression_Parser.cpp
#include<stdio.h>
#include<string.h>
#include<math.h>

constdoublePI=3.141592654;

//将角度转换成弧度
doubledegTorad(doubledeg)
{
return(2*PI*deg)/360;
}

//将中缀表达式转换为后缀表达式(逆波兰式)
voidtrans(chara[],charb[])
{
charstock[128]={0};

inttop=0;
intlen=0;
inti=0;
intj=0;

top=-1;
j=-1;
len=strlen(a);

for(i=0;i<len;i++)
{
switch(a[i])
{
case'(':
stock[++top]='(';
break;

case'+':
case'-':
while(top>=0&&stock[top]!='(')
{
b[++j]=stock[top--];
}
stock[++top]='';
stock[++top]=a[i];
break;

case'*':
case'/':
while(top>=0&&stock[top]!='('&&stock[top]!='+'&&stock[top]!='-')
{
b[++j]=stock[top--];
}
stock[++top]='';
stock[++top]=a[i];
break;

case's':
case'c':
case't':
while(top>=0&&stock[top]!='('&&stock[top]!='+'&&stock[top]!='-'&&stock[top]!='*'&&stock[top]!='/')
{
b[++j]=stock[top--];
}
stock[++top]='';
stock[++top]=a[i];
break;

case'v':
case'^':
while(top>=0&&stock[top]!='('&&stock[top]!='+'&&stock[top]!='-'&&stock[top]!='*'&&stock[top]!='/'&&stock[top]!='s'&&stock[top]!='c'&&stock[top]!='t')
{
b[++j]=stock[top--];
}
stock[++top]='';
stock[++top]=a[i];
break;

case'L':
while(top>=0&&stock[top]!='('&&stock[top]!='+'&&stock[top]!='-'&&stock[top]!='*'&&stock[top]!='/'&&stock[top]!='s'&&stock[top]!='c'&&stock[top]!='t'&&stock[top]!='v'&&stock[top]!='^')
{
b[++j]=stock[top--];
}
stock[++top]='';
stock[++top]=a[i];
break;

case')':
while(stock[top]!='(')
{
b[++j]=stock[top--];
}
top--;
break;

default:
b[++j]=a[i];
if(i==len-1||a[i+1]<'0'||a[i+1]>'9')
{
if(a[i+1]!='.')
{
b[++j]='';
}
}
break;
}
}

while(top>=0)
{
b[++j]=stock[top--];
}

b[++j]='';
}

//求解后缀表达式(逆波兰式)的值
doublecompvalue(charexp[])
{
inttop=0;
intlen=0;
inti=0;
intc=0;

doublesum=0;
doubledigit[128]={0};

charstr_num_temp[128]={0};

top=-1;
len=strlen(exp);

for(i=0;i<len;i++)
{
switch(exp[i])
{
case'':
break;

case'+':
sum=digit[top]+digit[top-1];
digit[--top]=sum;
break;

case'-':
sum=digit[top-1]-digit[top];
digit[--top]=sum;
break;

case'*':
sum=digit[top]*digit[top-1];
digit[--top]=sum;
break;

case'/':
sum=digit[top-1]/digit[top];
digit[--top]=sum;
break;

case's':
sum=sin(degTorad(digit[top]));
digit[top]=sum;
break;

case'c':
sum=cos(degTorad(digit[top]));
digit[top]=sum;
break;

case't':
sum=tan(degTorad(digit[top]));
digit[top]=sum;
break;

case'v':
sum=sqrt(digit[top]);
digit[top]=sum;
break;

case'^':
sum=pow(digit[top-1],digit[top]);
digit[--top]=sum;
break;

case'L':
sum=log10(digit[top]);
digit[top]=sum;
break;

default:
c=0;
memset(str_num_temp,0,sizeof(str_num_temp));
while(exp[i]>='0'&&exp[i]<='9'||exp[i]=='.')
{
str_num_temp[c++]=exp[i];
i++;
}
str_num_temp[c]='';
digit[++top]=atof(str_num_temp);
break;
}
}

returndigit[0];
}

//解析数学表达式(供外界调用的接口)
doubleExpression_Parser(char*Expression)
{
chartemp[128]={0};

trans(Expression,temp);
returncompvalue(temp);
}


//**************************************************************************
//调用方法
//*************************************************************************

//main.cpp

#include<iostream>
usingnamespacestd;

doubleExpression_Parser(char*Expression);

intmain()
{
doubleresult=0;

charexp[]="t45-c60+s30+(-6)*3^4+L100+v4-8/2";
//cin>>exp>>endl;//取消改行注释,等待用户输入数学表达式
result=Expression_Parser(exp);
cout<<"表达式"<<exp<<"的计算结果为:"<<result<<endl;

cin.get();
return0;
}


//***************************************
//使用说明
//***************************************
优越性:
1、支持的数学运算符:+-*/sincostansqrtpowlog10

2、支持小数运算,运算数据类型为double(双精度)型

3、支持小括号()


实例:
a^b表示求a的b次方

va或av表示求a平方根
v(va)与avv等价表示对a求两次平方根,可以此类推,求a的偶次方根。

s30表示求30°的正弦值
注:其中π值取3.141592654

L100表示求100以10为底的对数
注:L要大写


局限性:
1、不支持负数。
解决办法:如果要求表达式-5*9,则可以写成(0-5)*9。总之是可以用括号解决的。

2、未进行表达式的正确性验证。


符号优先级:
L
v、^
s、c、t
*、/
+、-

注:s、c、t分别代表sin、cos、tan,v代表开方,^代表求平方,L代表以10为底求对数。


举例一个正确的表达式:t45-c60+s30+(-6)*3^4+L100+v4-8/2

(赠言:你可在网络搜索“c++ 数学表达式解析”,还会有很多算法可以参考)

8. 编译原理究竟有没有用对编程的人

我跟你说,编译原理太有用了。
我是做手机游戏的,现在做一个游戏引擎。既然是引擎,就需要提供抽象的东西给上层使用。这里,我引入了脚本系统。
这个脚本系统包括一堆我根据实际需求自行设计的指令集,包括基本的输入输出,四则运算,系统功能调用,函数声明,调用等等(其实你要是用过lua或者其他游戏脚本你就知道了。)整个结构包括指令集、编译器、虚拟机等部分。这样,引擎提供一些基础服务,比如绘图,计算位置等,脚本就可以非常简单控制游戏。甚至快速构建新游戏。你应该知道QUAKE引擎吧?
这里提供给你一个计算器的小程序,应用了EBNF理论,支持表达式,比如(2+3*6)*4+4,你自己体验一下它的简洁和强大。
/*
simple integer arithmetic calculator according to the EBNF
<exp> -> <term>{<addop><term>}
<addop>->+|-
<term>-><factor>{<mulop><factor>}
<mulop> -> *
<factor> -> ( <exp> )| Number
Input a line of text from stdin
Outputs "Error" or the result.
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

char token;/*global token variable*/
/*function prototypes for recursive calls*/
int exp(void);
int term(void);
int factor(void);

void error(void)
{
fprintf(stderr,"Error\n");
exit(1);
}

void match(char expectedToken)
{
if(token==expectedToken)token=getchar();
else error();
}

main()
{
int result;
token = getchar();/*load token with first character for lookahead*/
result = exp();
if(token=='\n')/*check for end of line */
printf("Result = %d\n",result);
else error();/*extraneous cahrs on line*/
return 0;
}

int exp(void)
{
int temp = term();
while((token=='+')||(token=='-'))
switch(token)
{
case '+':
match('+');
temp+=term();
break;
case '-':
match('-');
temp-=term();
break;
}
return temp;
}

int term(void)
{
int temp = factor();
while (token=='*')
{
match('*');
temp*=factor();
}
return temp;
}

int factor(void)
{
int temp;
if(token=='('){
match('(');
temp = exp();
match(')');
}
else if(isdigit(token)){
ungetc(token,stdin);
scanf("%d",&temp);
token = getchar();
}
else error();
return temp;
}
其实编程学到一定程度总是没有方向了,总是在问学C/C++下一步怎么学啊,觉得掌握了该语言了云云,实际上,你缺少的就是这些软的东西,缺少的是理论。
编译原理不是单一的理论,它涵盖了一个niche,里面可以学到很多其他知识,比如正则表达式、BNF、EBNF、分析树、语法树还有很多运行时环境等知识
这些给你带来的是非常丰厚的回报。不说多了,学完运行时,你就会加深对C++语言本身的理解。
你要想有好的发展,还是学吧。

9. 怎么学习ollydbg原理是什么基本使用方法是什么

最简单的方法是启动OllyDbg,点击File|Open,然后选择你想调试的程序。程序需要命令行参数输入对话框下方的文本栏。
重新开始调试最后一个程序的快捷键是Ctrl+F2,并且OllyDbg使用相同的参数。
你也可以点选历史记录。把程序拖入OllyDbg也可以开始调试。
当然,当启动OllyDbg时,你在命令行中也能指定被调试的程序名和参数。比如:
你可以创建桌面快捷方式指向OllyDbg,选择属性,到快捷方式,把程序名加入目
标栏。每次你双击这个快捷图标,OllyDbg自动装载被调试程序。
你可以attach OllyDbg到某个正在运行的进程。点击File|Attach,从列表中选择
该进程。注意:当你关闭OllyDbg,这个进程也会终止。不要试图attach系统进程
,这很可能使系统完全死机。(事实上,大多数情况下,OS不允许attach敏感进
程)
OllyDbg能作为just-in-time debugger。这需要在注册表中登记。点击
Options|Just-in-time debugging,在对话框中按“Make OllyDbg just-in-time
debugger”。现在,当一些程序崩溃,你会被询问是否调试它。这样,操作系统
可以启动OllyDbg并直接停在异常发生处。如果你选择attaching without
confirmation,OllyDbg不会询问直接启动。要恢复原来的just-in-time
debugger,在出现的对话框中按相应的按纽就行了。
其它方法还有,把OllyDbg加入可执行文件的弹出式菜单。点击Options|Add to
Explorer,按“Add OllyDbg to menu in Windows Explorer”。以后你可以右击
可执行文件点选OllyDbg。这个选项创建注册表键
HKEY_CLASSES_ROOT/exefile/shell/Open with OllyDbg and
HKEY_CLASSES_ROOT/exefile/shell/Open with OllyDbg/command
OllyDbg可以调试控制台(基于文本)程序。
注意:WindowsNT或Windows2000下,你必须有管理员权限
OllyDbg的help-通用快捷键(翻译)
Golbal shortcuts(通用快捷键)
这些快捷键在OllyDbg中通用,不依赖于当前活动窗口。
Ctrl+F2---OllyDbg重置,重新开始调试。如果没有活动程序,OllyDbg装入历史列表中的第一个程序。OllyDbg重置会释放内存移除硬断点。
Alt+F2--关闭被调试的程序。如果程序还在活动状态,你会被询问是否执行该操作。
F3--显示“Open 32-bit .exe file”对话框,这里可以选择可执行文件和指定参数
Alt+F5--使OllyDbg显示在屏幕最前方。如果被调试程序中断时显示窗口遮住OllyDbg的一些区域,不继续运行又不能移动或最小化它。激活OllyDbg按Alt+F5可以解决。如果你再次按Alt+F5,OllyDbg会恢复为普通窗口。OllyDbg的当前状态显示在状态栏。
F7--step into,执行下一条简单命令。如果该命令是一个函数调用,进入调用函数内部。如果命令有REP前缀,执行该命令的一步操作。
Shift+F7--与F7相同,除了当被调试程序遇到某些异常时,首先尝试调用程序自己的异常处理过程。
Ctrl+F7--animate into,一步一步执行程序,也进入函数调用(就象你一直按着F7,不过更快)。当你执行一些单步或继续命令,程序到达有效断点,一些异常发生时,Animation终止。每步执行,OllyDbg重画所有窗口。要加速animation,关闭所有窗口而不要只改变现有窗口的大小。终止animation,也可按Esc。
F8-step over,执行下一条简单命令。如果该命令是一个函数调用,立刻执行完该函数(除非函数内部有断点或产生异常)如果命令有REP前缀,执行所有重复操作,并停于下一条命令。
Shift+F8--与F8相同,除了当被调试程序遇到某些异常时,首先尝试调用程序自己的异常处理过程。
Ctrl+F8--animate over,一步一步执行程序,但不进入函数调用(就象你一直按着F8,不过更快)。当你执行一些单步或继续命令,程序Animation到达有效断点或异常发生时,Animation终止。每步执行,OllyDbg重画所有窗口。要加速animation,关闭所有窗口而不要只改变现有窗口的大小。终止animation也可按Esc。
F9--继续执行程序。
Shift+F9--与F9相同。除了当被调试程序遇到某些异常时,首先尝试调用程序自己的异常处理过程。
Ctrl+F11--run trace into,一步一步执行程序,要进入函数调用,记录寄存器内容。Run trace 不重绘CPU窗口.
F12-悬挂所有线程以停止程序执行。最好用继续键和菜单命令(像F9)恢复执行线程,而不要用其它手动方法恢复。
Ctrl+F12--run trace over,一步一步执行程序,不进入函数调用,记录寄存器内容。Run trace不重绘CPU窗口。
ESC--如果animation或跟踪正在进行,将被终止。如果CPU窗口显示跟踪时的数据,此时转为显示实际数据。
Alt+B--打开或恢复Breakpoint窗口。这里可以编辑,删除和观察断点。
Alt+C--打开或恢复CPU窗口。
Alt+E--打开或恢复模块列表
Alt+E--打开或恢复Call stack窗口。
Alt+L--打开或恢复Log窗口。
Alt+M--打开或恢复Memory窗口。
Alt+O--打开Option对话框
Ctrl+P--打开Patch窗口。
Ctrl+T--打开Pause run trace对话框
Alt+X-中断OllyDbg。
多数窗口可以使用下列快捷键:
Alt+F3--关闭活动窗口。
Ctrl+F4--关闭活动窗口。
F5--最大化或恢复活动窗口。
F6--激活下一个窗口。
Shift+F6--激活前一个窗口。
F10--打开激活窗口或面板的右键菜单。
LeftArrow--左移一个字符。
Ctrl+LeftArrow--左移一行。
RightArrow--右移一个字符。
Ctrl+RightArrow--右移一行。
OllyDbg的help-分析模块介绍(翻译)
分析
OllyDbg集成了快速超强的代码分析器。装载它,可以用弹出式菜单或者CPU窗口
的反汇编栏按Ctrl+A或者在执行模块选“Analyze all moles”。
分析器非常有用。它在数据中分辨代码,标记入口点和jump的目标,辨认switch
tables,ASCII和UNICODE字符串,定位过程、循环、高级switch语句和解码标准
API函数参数(看范例)。OllyDbg的其它部分也广泛用于数据分析。
这怎么可能呢?我稍微介绍一下原理。首先,OllyDbg反汇编代码区所有可能的地
址,记下所有发现的调用及指向的目标。当然,许多这样的调用不正确,但是未
必会有两个错误的调用指向同一条命令,并且三个或三个以上更不可能。这样,
三个或更多调用指向同一地址,我就确信该地址是经常使用的子过程入口。从这
个入口开始,我跟踪所有的跳转和调用,反复操作。这种方法使我99.9%确定所
有命令。然而,某些字节不在这条链中,我采用大约20个更高效的方法(最简单
的如:“MOV [RA],Ra"是无效命令).
过程检测也简单。过程,从分析器的角度看,就是从入口开始的代码的连续区域
,(理论上)可以到达其它命令(除NOP或对齐填充外)。你可以指定三种识别级
。Strict级严格确认一个入口和至少一个出口。heuristical级,分析器尝试确认
入口。如果你选择fuzzy级,或多或少相容的代码区被分离为过程。现代编译器把
过程分成几个部分作公用代码优化。这种情况下,fuzzy级特别有用!然而,误解
的概率也相当高。
类似的,loop是一个封闭的连续命令序列,这里最后的命令跳到开头、一个入口
几个出口。Loop相当于高级操作语言中的do,while和for。OllyDbg能认识任何复
杂的嵌套循环。在反汇编区,他们用长长的大括号标记。如果入口不是循环的第
一条命令,OllyDbg用个小三角形作标记。
实现switch语句,多数编译器把switch变量装入寄存器,然后减去一部分,像下
面代码序列一样:
MOV EDX,<switch variable>
SUB EDX,100
JB DEFAULTCASE
JE CASE100 ; Case 100
DEC EDX
JNE DEFAULTCASE
... ; Case 101
这些序列也可能包含一级或两级switch表,直接比较,优化,填充等等。如果你
深入研究比较和跳转树,很难说哪一条命令是某个case语句。OllyDbg为你代劳。
它标记所有的case语句,包括default,甚至尝试猜测case的意思,如'A',
WM_PAINT 或者 EXCEPTION_ACCESS_VIOLATION。如果命令序列不修改寄存器(只
由比较命令构成),那么不大可能是switch语句,但可能是if嵌套:
if (i==0) {...}
else if (i==5) {...}
else if (i==10) {...}
让OllyDbg解码if嵌套为switch,选择Analysis1中相应的选项。
OllyDbg预置超过1900个常用API函数的描述。包括KERNEL32, GDI32, USER32,
ADVAPI32, COMDLG32, SHELL32, VERSION, SHLWAPI, COMCTL32, WINSOCK,
WS2_32 和 MSVCRT。你也可以加入自己的描述。如果分析器遇到已知函数名的调
用(或跳转到该函数),它尝试解码调用跟前的PUSH命令。因此,你可以粗略翻
译该调用的功能。OllyDbg也内置大约400个标准C函数的描述。如果你利用新库,
我建议你分析前先扫描对象文件。这种情况下,OllyDbg也会解码已知的C函数参
数。
如果选项“Guess number of arguments of unknown functions”被设置,分析
器尝试确认调用过程进栈的双字数目,并标记他们为参数Arg1,Arg2等等。注意:
如果有寄存器参数,OllyDbg还是不认识也不包括在上面的统计中。分析器采用了
一个安全的方法。例如,它不分辨无参数过程和返回前用POP恢复寄存器代替舍弃
参数的case语句。然而,能分辨出的函数数目相当多,并非常有助于提高代码的
可读性。
分析器能跟踪寄存器的值。现代优化编译器,特别是面向Pentium的,经常把常量
和地址装入寄存器便于重复使用或减小内存占用空间。如果一些常量装入寄存器
,分析器会注意它,并用于解码函数及其参数。还能执行简单的算术计算跟踪
push和pop命令。
分析器不能区别不同类型的名字。如果你用已有的名字命名一些函数,OllyDbg会
解码所有该地址的调用为原过程。WinMain,DllEntryPoint和WinProc是特殊的预
定义名。你可以使用这些标号标记主程序入口,DLL入口指针和window过程(注意
:OllyDbg不会检查用户定义标号的唯一性)。当然,最好的方法是显示已定义的
参数。
非常不幸,没有一般的规则用于100%的准确分析。有些情况下,例如当模块包含
p-代码或者代码区嵌入大量数据,分析器可能认为部分数据是代码。如果统计分
析显示代码可能被打包或加密,分析器会警告你。如果你想用hit跟踪方式,我建
议你不要用fuzzy分析方式,否则断点被设置在被误认为代码的数据上的几率很高。
解压文件通常在主体代码外有解压代码。如果你选择SFX选项“Extend code
section to include self-extractor”,OllyDbg会扩大代码区,形式上允许分
析它并跟踪。
OllDbg的一般原理(翻译)部分
我希望你熟悉80x86兼容CPU的内部结构,并且有汇编写程序的经历。我也希望你
熟悉Microsoft Windows.
OllyDbg是一个单进程多线程的“机器代码级”debugger,用于Windows环境下的32位程序。它允许你debug和patch PE格式的可执行程序。OllDbg仅仅使用列入文档的Win32 API调用,所以可用于下一代32位Windows系统。OllDbg看来也可工作于Windows XP,但是我没有详尽的测试,因此不能保证功能完整。
OllyDbg不是面向编译器。它不含特别的规则显示某些情况下特定的编译程序生成哪些代码序列。因此,你可以一样对待任何编译器编译的,或者汇编书写的任何代码。
OllyDbg与被调试的程序同时工作。你可以浏览代码和数据、设置断点、停止或继续线程,甚至运行期修改内存(有时这叫作软调试方式)。当然,如果被请求的操作不是最基本的,OllyDbg就会短时暂停程序,但这对用户透明。有时不在调试状态运行的程序会意外崩溃。OllyDbg,这个“及时”debugger,会指出异常发生的位置。
OllyDbg强烈面向模块。模块这里指启动时加载的或动态加载的主执行文件或动态连接库。在调试区,你可以设置断点,定义新标号和注释汇编语句。当一些模块从内存卸载后,OllyDbg保存这些信息到扩展名为.UDD名字同被调试模块的文件中。下次当装载这些模块时,OllyDbg自动复原所有调试信息,不论程序是否使用这些模块。比如:你调试使用Mydll的程序Myprog1,并且在Mydll中设置一些断点。那么当你调试Myprog2时,也使用Mydll,你会发现所有在Mydll中的断点还在那里,不管Mydll是否装载在不同的位置。
一些调试器把被调试进程的内存视为单个2**32字节区域。OllyDbg做了别的处理方法。内存由几个独立的块组成。任何内存操作都限制于块内。在大多数案例中,这工作优良并且容易调试。但是模块包含几个执行部分等等,你将不能立刻看到整个代码。然而这些例外不常见。
OllyDbg是内存消耗大户。启动时就要分配3MB内存,甚至更多。每次分析,备份,跟踪或文件转储另外再分配。所以当你调试大工程时消耗40或60M内存很正常。
要有效的调试一些无源代码的程序,你首先必须理解它是如何工作的。OllyDbg提供了大量的手段使理解更容易

10. C语言实现,从键盘输入一个x的显性表达式,如6x,sin5x等,然后给出x的范围,计算x的结果并且画出图象。

第一,要能从语法上识别作为表达式输入的字符串,这个需要编译原理相关的知识和技巧,当然硬着来也是可以的,要建立一个表达式的树形结构,才能方便计算,这个难度应该是这个程序里最大的
第二,把x的取值范围映射到显示的图像宽度上,确定每列像素上x的值,把这些x值代入表达式树,计算出y值,把所有(x, y)再转换成图像的像素坐标,这个是很容易的步骤
第三,把所有像素坐标的(x, y)显示出来,这个是平台相关的,不同平台都不一样,难度虽然不会大,但如果不熟悉选定的平台,可能要多花些时间

阅读全文

与编译原理exp相关的资料

热点内容
算法如何规制 浏览:866
单片机继电器驱动 浏览:649
小薯仔编程软件下载 浏览:153
单片机opencv 浏览:255
千锋python人工智能培训 浏览:856
合理的文件夹划分 浏览:258
十点读书app哪里下载 浏览:964
uu跑腿押金上app在哪里解约 浏览:37
华为如何将app移到桌面 浏览:597
阿里安卓面试算法题 浏览:705
语文知识手册pdf 浏览:841
为什么安卓手机oled屏很白很亮 浏览:252
如何找回iphone手机隐藏的app 浏览:21
linuxc多进程 浏览:649
android飞行游戏 浏览:965
数据挖掘常见算法 浏览:135
python单实例化 浏览:351
str中python 浏览:89
java的equals用法 浏览:845
奥维云服务器怎么开通 浏览:171