導航:首頁 > 源碼編譯 > 編譯原理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相關的資料

熱點內容
phpsae源碼 瀏覽:853
為什麼安卓手機一直要許可權 瀏覽:227
匯編程序的偽指令 瀏覽:803
蘋果7怎麼更新app 瀏覽:318
c語言常用演算法pdf 瀏覽:960
編程如何讓畫面動起來 瀏覽:865
大齡女程序員未來發展 瀏覽:976
數學書籍pdf 瀏覽:506
加密門禁卡寫入成功無法開門 瀏覽:464
齒輪傳動pdf 瀏覽:52
alpinelinux 瀏覽:150
手機端app的掃碼功能在哪裡 瀏覽:227
少兒編程中小班英語教案 瀏覽:452
鎖屏密碼加密手機怎麼解除 瀏覽:205
linuxlostfound 瀏覽:135
征途伺服器ip地址 瀏覽:330
git提交代碼命令行 瀏覽:165
什麼叫瀏覽器伺服器結構 瀏覽:157
於謙聊天哪個app 瀏覽:449
小鵬汽車nlp演算法工程師薪資 瀏覽:881