導航:首頁 > 源碼編譯 > 編譯原理實驗測試程序

編譯原理實驗測試程序

發布時間:2023-06-30 01:02:46

1. 急求!!!用C語言編寫一個編譯原理實驗的簡單優先分析法程序

編譯原理IF條件語句的翻譯程序設計—簡單優先法、輸出四元式通過設計、編制、調試一個條件語句的語法及語義分析程序,加深對語法及語義分析原理的理解,並實現詞法分析程序對單詞序列的詞法檢查和分析。具體做到以下幾點:①對輸入語句進行詞法分析。將輸入的字元串進行掃描和分解,識別出一個個合法的單詞。單詞種類包括:關鍵字,標識符,運算符,常數和界限符②進行語法分析。編寫條件語句的相應文法,按照語法分析方法中的簡單優先分析法為文法設計簡單優先表,對詞法分析得到的單詞序列進行語法分析,以判別輸入的語句是否屬於該文法的條件語句。③語法制導翻譯。設計中間代碼(四元式)序列的結構及屬性文法,運用語法制導翻譯,在進行語法分析的同時,執行相應的語義規則描述的動作,從而實現語義處理,生成中間代碼以四元式的形式輸出。④錯誤提示。對不同的錯誤給出簡略描述,並終止程序的繼續執行。下載地址如下,有你要的東西!pile.rar

2. 急需編譯原理的一些程序

// the scanner implementation for the TINY compiler
#include "globals.h"
#include "util.h"
#include "scan.h"

//states in scanner DFA
typedef enum
{
START,INASSIGN,INCOMMENT,INNUM,INID,DONE
}StateType;

//lexeme of identifier or reserved word
char tokenString[MAXTOKENLEN+1];

//BUFLEN = lenght of the input buffer for source code lines
#define BUFLEN 256

static char lineBuf[BUFLEN];//holds the current lines
static int linepos = 0; //current position in linebuf
static int bufsize = 0;//current size of buffer string

//getNextChar fetches the next non-blank character from lineBuf
//reading in a new line if lineBuf is exhausted
static char getNextChar(void)
{
if(!(linepos<bufsize))
{
lineno++;
if (fgets(lineBuf,BUFLEN-1,source))
{
if(EchoSource)
fprintf(listing,"%d:%s",lineno,lineBuf);
bufsize = strlen(lineBuf);
linepos = 0;
return lineBuf[linepos++];
}
else return EOF;
}
else return lineBuf[linepos++];
}

//ungetNextChar backtracks one character in linebuf
static void ungetNextChar(void)
{
linepos--;
}

//lookup table of reserved words
static struct
{
char* str;
TokenType tok;
}reservedWords[MAXRESERVED]
={{"if",IF},{"then",THEN},{"else",ELSE},{"end",END},
{"repeat",REPEAT},{"until",UNTIL},{"read",READ},{"write",WRITE}};

//lookup an identifier to see if it is a reserved word
//uses linear search
static TokenType reservedLookup(char* s)
{
int i;
for(i=0;i<MAXRESERVED;i++)
if(!strcmp(s,reservedWords[i].str))
return reservedWords[i].tok;
return ID;
}

// the primary function of the scanner

//function getToken returns the next token in source file
TokenType getToken(void)
{
//index for storing into tokenString
int tokenStringIndex = 0;
//holds current token to be returned
TokenType currentToken;
//current state - always begins at START
StateType state = START;
//flag to indicate save to tokenString
int save;
while (state!=DONE)
{
char c = getNextChar();
save = TRUE;
switch(state)
{
case START:
if(isdigit(c))
state = INNUM;
else if(isalpha(c))
state = INID;
else if(c==':')
state = INASSIGN;
else if((c==' ')||(c=='\t')||(c=='\n'))
save = FALSE;
else if(c=='{')
{
save = FALSE;
state = INCOMMENT;
}
else{
state = DONE;
switch(c)
{
case EOF:
save = FALSE;
currentToken = ENDFILE;
break;
case '=':
currentToken = EQ;
break;
case '<':
currentToken = LT;
break;
case '+':
currentToken = PLUS;
break;
case '-':
currentToken = MINUS;
break;
case '*':
currentToken = TIMES;
break;
case '/':
currentToken = OVER;
break;
case '(':
currentToken = LPAREN;
break;
case ')':
currentToken = RPAREN;
break;
case ';':
currentToken = SEMI;
break;
default:
currentToken = ERROR;
break;
}
}
break;
case INCOMMENT:
save = FALSE;
if(c=='}')state = START;
break;
case INASSIGN:
state = DONE;
if(c=='=')
currentToken = ASSIGN;
else{
//backup in the input
ungetNextChar();
save = FALSE;
currentToken = ERROR;
}
break;
case INNUM:
if(!isdigit(c))
{
//backup in the input
ungetNextChar();
save = FALSE;
state = DONE;
currentToken = NUM;
}
break;
case INID:
if(!isalpha(c))
{
//backup in the input
ungetNextChar();
save = FALSE;
state = DONE;
currentToken = ID;
}
break;
case DONE:
default://should never happen
fprintf(listing, "Scanner Bug: state = %d\n",state);
state = DONE;
currentToken = ERROR;
break;
}
if((save)&&(tokenStringIndex <= MAXTOKENLEN))
tokenString[tokenStringIndex++] = c;
if (state == DONE)
{
tokenString[tokenStringIndex] = '\0';
if(currentToken == ID)
currentToken = reservedLookup(tokenString);
}
}
if(TraceScan){
fprintf(listing,"\t%d:",lineno);
printToken(currentToken,tokenString);
}
return currentToken;
}//end getToken
太長了,寫不過來,這只是一個非常簡單非常簡單的詞法分析部分的實現。
另附NFA->DFA的帖子,CSDN的。

3. 編譯原理實驗「C語言」檢查某段C源程序中,標識符的使用是否正確,即是否先聲明後使用,或

#include "stdio.h" /*定義I/O庫所用的某些宏和變數*/
#include "string.h" /*定義字元串庫函數*/
#include "conio.h" /*提供有關屏幕窗口操作函數*/
#include "ctype.h" /*分類函數*/
char prog[80]=,
token[8]; /*存放構成單詞符號的字元串*/
char ch;
int syn, /*存放單詞字元的種別碼*/
n,
sum, /*存放整數型單詞*/
m,p; /*p是緩沖區prog的指針,m是token的指針*/
char *rwtab[6]=;
void scaner(){
m=0;
sum=0;
for(n=0;n<8;n++)
token[n]='\0';
ch=prog[p++];
while(ch==' ')
ch=prog[p++];
if(isalpha(ch)) /*ch為字母字元*/{
while(isalpha(ch)||isdigit(ch)) /*ch 為字母字元或者數字字元*/{
token[m++]=ch;
ch=prog[p++];}
token[m++]='\0';
ch=prog[p--];
syn=10;
for(n=0;n<6;n++)
if(strcmp(token,rwtab[n])==0) /*字元串的比較*/{
syn=n+1;
break;}}
else
if(isdigit(ch)) /*ch是數字字元*/{
while(isdigit(ch)) /*ch是數字字元*/{
sum=sum*10+ch-'0';
ch=prog[p++];}
ch=prog[p--];
syn=11;}
else
switch(ch){
case'<':m=0;token[m++]=ch;ch=prog[p++];
if(ch=='>'){
syn=21;
token[m++]=ch;}
else if(ch=='='){
syn=22;
token[m++]=ch;}
else{
syn=20;
ch=prog[p--];}
break;
case'>':m=0;token[m++]=ch;ch=prog[p++];
if(ch=='='){
syn=24;
token[m++]=ch;}
else{
syn=23;
ch=prog[p--];}
break;
case':':m=0;token[m++]=ch;ch=prog[p++];
if(ch=='='){
syn=18;
token[m++]=ch;}

else{
syn=17;
ch=prog[p--];}
break;
case'+':syn=13;token[0]=ch;break;
case'-':syn=14;token[0]=ch;break;
case'*':syn=15;token[0]=ch;break;
case'/':syn=16;token[0]=ch;break;
case'=':syn=25;token[0]=ch;break;
case';':syn=26;token[0]=ch;break;
case'(':syn=27;token[0]=ch;break;
case')':syn=28;token[0]=ch;break;
case'#':syn=0;token[0]=ch;break;
default:syn=-1;}}
main()
{
printf("\n\nThe significance of the figures:\n"
"1.figures 1 to 6 said Keyword\n"
"2.figures 10 and 11 said Other indicators\n"
"3.figures 13 to 28 said Operators\n");

p=0;

printf("\nplease input string:\n");
do {
ch=getchar();
prog[p++]=ch;
}while(ch!='#');

p=0;

do{
scaner();
switch(syn){
case 11: printf("(%d,%d)\n",syn,sum);break;
case -1: printf("\n ERROR;\n");break;
default: printf("(%d,%s)\n",syn,token);
}
}while(syn!=0);

getch();
}
程序測試結果
對源程序begin x:=9: if x>9 then x:=2*x+1/3; end #的源文件,經過詞法分析後輸出如下圖5-1所示:

具體的你在修改修改吧

4. 編譯原理

C語言編譯過程詳解
C語言的編譯鏈接過程是要把我們編寫的一個C程序(源代碼)轉換成可以在硬體上運行的程序(可執行代碼),需要進行編譯和鏈接。編譯就是把文本形式源代碼翻譯為機器語言形式的目標文件的過程。鏈接是把目標文件、操作系統的啟動代碼和用到的庫文件進行組織形成最終生成可執行代碼的過程。過程圖解如下:

從圖上可以看到,整個代碼的編譯過程分為編譯和鏈接兩個過程,編譯對應圖中的大括弧括起的部分,其餘則為鏈接過程。
一、編譯過程
編譯過程又可以分成兩個階段:編譯和匯編。
1、編譯
編譯是讀取源程序(字元流),對之進行詞法和語法的分析,將高級語言指令轉換為功能等效的匯編代碼,源文件的編譯過程包含兩個主要階段:
第一個階段是預處理階段,在正式的編譯階段之前進行。預處理階段將根據已放置在文件中的預處理指令來修改源文件的內容。如#include指令就是一個預處理指令,它把頭文件的內容添加到.cpp文件中。這個在編譯之前修改源文件的方式提供了很大的靈活性,以適應不同的計算機和操作系統環境的限制。一個環境需要的代碼跟另一個環境所需的代碼可能有所不同,因為可用的硬體或操作系統是不同的。在許多情況下,可以把用於不同環境的代碼放在同一個文件中,再在預處理階段修改代碼,使之適應當前的環境。
主要是以下幾方面的處理:
(1)宏定義指令,如 #define a b。
對於這種偽指令,預編譯所要做的是將程序中的所有a用b替換,但作為字元串常量的 a則不被替換。還有 #undef,則將取消對某個宏的定義,使以後該串的出現不再被替換。
(2)條件編譯指令,如#ifdef,#ifndef,#else,#elif,#endif等。
這些偽指令的引入使得程序員可以通過定義不同的宏來決定編譯程序對哪些代碼進行處理。預編譯程序將根據有關的文件,將那些不必要的代碼過濾掉
(3) 頭文件包含指令,如#include "FileName"或者#include <FileName>等。
在頭文件中一般用偽指令#define定義了大量的宏(最常見的是字元常量),同時包含有各種外部符號的聲明。採用頭文件的目的主要是為了使某些定義可以供多個不同的C源程序使用。因為在需要用到這些定義的C源程序中,只需加上一條#include語句即可,而不必再在此文件中將這些定義重復一遍。預編譯程序將把頭文件中的定義統統都加入到它所產生的輸出文件中,以供編譯程序對之進行處理。包含到C源程序中的頭文件可以是系統提供的,這些頭文件一般被放在/usr/include目錄下。在程序中#include它們要使用尖括弧(<>)。另外開發人員也可以定義自己的頭文件,這些文件一般與C源程序放在同一目錄下,此時在#include中要用雙引號("")。
(4)特殊符號,預編譯程序可以識別一些特殊的符號。
例如在源程序中出現的LINE標識將被解釋為當前行號(十進制數),FILE則被解釋為當前被編譯的C源程序的名稱。預編譯程序對於在源程序中出現的這些串將用合適的值進行替換。
預編譯程序所完成的基本上是對源程序的「替代」工作。經過此種替代,生成一個沒有宏定義、沒有條件編譯指令、沒有特殊符號的輸出文件。這個文件的含義同沒有經過預處理的源文件是相同的,但內容有所不同。下一步,此輸出文件將作為編譯程序的輸出而被翻譯成為機器指令。
第二個階段編譯、優化階段。經過預編譯得到的輸出文件中,只有常量;如數字、字元串、變數的定義,以及C語言的關鍵字,如main,if,else,for,while,{,}, +,-,*,\等等。
編譯程序所要作得工作就是通過詞法分析和語法分析,在確認所有的指令都符合語法規則之後,將其翻譯成等價的中間代碼表示或匯編代碼。
優化處理是編譯系統中一項比較艱深的技術。它涉及到的問題不僅同編譯技術本身有關,而且同機器的硬體環境也有很大的關系。優化一部分是對中間代碼的優化。這種優化不依賴於具體的計算機。另一種優化則主要針對目標代碼的生成而進行的。
對於前一種優化,主要的工作是刪除公共表達式、循環優化(代碼外提、強度削弱、變換循環控制條件、已知量的合並等)、復寫傳播,以及無用賦值的刪除,等等。
後一種類型的優化同機器的硬體結構密切相關,最主要的是考慮是如何充分利用機器的各個硬體寄存器存放的有關變數的值,以減少對於內存的訪問次數。另外,如何根據機器硬體執行指令的特點(如流水線、RISC、CISC、VLIW等)而對指令進行一些調整使目標代碼比較短,執行的效率比較高,也是一個重要的研究課題。
2、匯編
匯編實際上指把匯編語言代碼翻譯成目標機器指令的過程。對於被翻譯系統處理的每一個C語言源程序,都將最終經過這一處理而得到相應的目標文件。目標文件中所存放的也就是與源程序等效的目標的機器語言代碼。目標文件由段組成。通常一個目標文件中至少有兩個段:
代碼段:該段中所包含的主要是程序的指令。該段一般是可讀和可執行的,但一般卻不可寫。
數據段:主要存放程序中要用到的各種全局變數或靜態的數據。一般數據段都是可讀,可寫,可執行的。
UNIX環境下主要有三種類型的目標文件:
(1)可重定位文件
其中包含有適合於其它目標文件鏈接來創建一個可執行的或者共享的目標文件的代碼和數據。
(2)共享的目標文件
這種文件存放了適合於在兩種上下文里鏈接的代碼和數據。
第一種是鏈接程序可把它與其它可重定位文件及共享的目標文件一起處理來創建另一個 目標文件;
第二種是動態鏈接程序將它與另一個可執行文件及其它的共享目標文件結合到一起,創建一個進程映象。
(3)可執行文件
它包含了一個可以被操作系統創建一個進程來執行之的文件。匯編程序生成的實際上是第一種類型的目標文件。對於後兩種還需要其他的一些處理方能得到,這個就是鏈接程序的工作了。
二、鏈接過程
由匯編程序生成的目標文件並不能立即就被執行,其中可能還有許多沒有解決的問題。
例如,某個源文件中的函數可能引用了另一個源文件中定義的某個符號(如變數或者函數調用等);在程序中可能調用了某個庫文件中的函數,等等。所有的這些問題,都需要經鏈接程序的處理方能得以解決。
鏈接程序的主要工作就是將有關的目標文件彼此相連接,也即將在一個文件中引用的符號同該符號在另外一個文件中的定義連接起來,使得所有的這些目標文件成為一個能夠被操作系統裝入執行的統一整體。
根據開發人員指定的同庫函數的鏈接方式的不同,鏈接處理可分為兩種:
(1)靜態鏈接
在這種鏈接方式下,函數的代碼將從其所在地靜態鏈接庫中被拷貝到最終的可執行程序中。這樣該程序在被執行時這些代碼將被裝入到該進程的虛擬地址空間中。靜態鏈接庫實際上是一個目標文件的集合,其中的每個文件含有庫中的一個或者一組相關函數的代碼。
(2) 動態鏈接
在此種方式下,函數的代碼被放到稱作是動態鏈接庫或共享對象的某個目標文件中。鏈接程序此時所作的只是在最終的可執行程序中記錄下共享對象的名字以及其它少量的登記信息。在此可執行文件被執行時,動態鏈接庫的全部內容將被映射到運行時相應進程的虛地址空間。動態鏈接程序將根據可執行程序中記錄的信息找到相應的函數代碼。
對於可執行文件中的函數調用,可分別採用動態鏈接或靜態鏈接的方法。使用動態鏈接能夠使最終的可執行文件比較短小,並且當共享對象被多個進程使用時能節約一些內存,因為在內存中只需要保存一份此共享對象的代碼。但並不是使用動態鏈接就一定比使用靜態鏈接要優越。在某些情況下動態鏈接可能帶來一些性能上損害。
我們在linux使用的gcc編譯器便是把以上的幾個過程進行捆綁,使用戶只使用一次命令就把編譯工作完成,這的確方便了編譯工作,但對於初學者了解編譯過程就很不利了,下圖便是gcc代理的編譯過程:

從上圖可以看到:
預編譯
將.c 文件轉化成 .i文件
使用的gcc命令是:gcc –E
對應於預處理命令cpp
編譯
將.c/.h文件轉換成.s文件
使用的gcc命令是:gcc –S
對應於編譯命令 cc –S
匯編
將.s 文件轉化成 .o文件
使用的gcc 命令是:gcc –c
對應於匯編命令是 as
鏈接
將.o文件轉化成可執行程序
使用的gcc 命令是: gcc
對應於鏈接命令是 ld
總結起來編譯過程就上面的四個過程:預編譯、編譯、匯編、鏈接。了解這四個過程中所做的工作,對我們理解頭文件、庫等的工作過程是有幫助的,而且清楚的了解編譯鏈接過程還對我們在編程時定位錯誤,以及編程時盡量調動編譯器的檢測錯誤會有很大的幫助的。
是否可以解決您的問題?

5. 編譯原理用C語言實現基於LR(1)或SLR(1)語法分析程序代碼,最好還有報告,急。。。

這個是精簡的語法分析程序,如果符合的話,hi我
給你實驗報告

#include <stdio.h>
#include<dos.h>
#include<stdlib.h>
#include<string.h>
char a[50] ,b[50];
char ch;
int n1,i1=0,n=5;
int E();int T();int E1();int T1();int F();
void main() /*遞歸分析*/
{
int f,j=0;
printf("請輸入字元串(長度<50,以#號結束)\n");
do{
scanf("%c",&ch);
a[j]=ch;
j++;
}while(ch!='#');
n1=j;
ch=b[0]=a[0];
f=E();
if (f==0) return;
if (ch=='#') printf("accept\n");
else printf("error\n");
}

int E() // E→TE'
{ int f,t;
f=T();
if (f==0) return(0);
t=E1();
if (t==0) return(0);
else return(1);
}

int T() // T→FT'
{ int f,t;
f=F();
if (f==0) return(0);
t=T1();
if (t==0) return(0);
else return(1);
}

int E1()/*E』*/ // E'→+TE'
{ int f;
if(ch=='+') {
b[i1]=ch;
ch=a[++i1];
f=T();
if (f==0) return(0);
E1();
return(1);
}
return(1);
}

int T1()/*T』*/ // T'→*FT'
{
int f,t;
if(ch=='*') {
b[i1]=ch;
ch=a[++i1];
f=F();
if (f==0) return(0);
t=T1();
if (t==0) return(0);
else return(1);}
a[i1]=ch;
return(1);
}

int F() // F→(E)
{ int f;
if(ch=='(') {
b[i1]=ch;
ch=a[++i1];
f=E();
if (f==0) return(0);
if(ch==')') {
b[i1]=ch;
ch=a[++i1];
}
else {
printf("error\n");
return(0);
}
}
else if(ch=='i') {
b[i1]=ch;
ch=a[++i1];
}
else {printf("error\n");return(0);}
return(1);
}

6. 編譯原理詞法分析程序

(一)Block子程序分析

procere enter(k: object1); //填寫符號表
begin {enter object into table}
tx := tx + 1; //下標加1,tx的初始值為零,零下標不地址不填寫標志符,用於查找失敗使用
with table[tx] do //填入內容,保存標志符名和類型
begin name := id; kind := k;
case k of //根據類型判斷是否正確
constant: begin if num > amax then //如果是常量,判斷是否大於最大值,若是則報30號錯
begin error(30); num :=0 end;
val := num //否則保存數值
end;
varible: begin level := lev; adr := dx; dx := dx + 1; //如果是變數,填寫變數內部表示,LEVEl是變數的層次,adr為地址
end;
proc: level := lev //如果是過程,保存過程的層次
end
end
end {enter};

//查找符號表的位置
function position(id: alfa): integer;
var i: integer;
begin {find indentifier id in table} //從後向前查找
table[0].name := id; i := tx; //找到保存類型
while table[i].name <> id do i := i-1;
position := i //返回標志符在符號表中的位置
end {position};

procere block(lev,tx: integer; fsys: symset);
var dx: integer; {data allocation index} //數據分配索引
tx0: integer; {initial table index} //初始符號表索引
cx0: integer; {initial code index} //初始代碼索引
procere enter(k: object1); //填寫符號表,下次分析
begin {enter object into table}
tx := tx + 1;
with table[tx] do
begin name := id; kind := k;
case k of
constant: begin if num > amax then
begin error(30); num :=0 end;
val := num
end;
varible: begin level := lev; adr := dx; dx := dx + 1;
end;
proc: level := lev
end
end
end {enter};

function position(id: alfa): integer; //查找符號表,下次分析
var i: integer;
begin {find indentifier id in table}
table[0].name := id; i := tx;
while table[i].name <> id do i := i-1;
position := i
end {position};

procere constdeclaration; //常量聲明
begin if sym = ident then //如果是標志符,讀入一個TOKEN
begin getsym;
if sym in [eql, becomes] then //讀入的是等號或符值號繼續判斷
begin if sym = becomes then error(1); //如果是「=」報1號錯
getsym; //讀入下一個TOKEN
if sym = number then //讀入的是數字,填寫符號表
begin enter(constant); getsym
end
else error(2) //如果不是數字,報2號錯
end else error(3) //不是等號或符值號,報3號錯
end else error(4) //如果不是標志符,報4號錯
end {constdeclaration};

procere vardeclaration; //變數聲明
begin if sym = ident then //讀入的是標志符,填寫符號表
begin enter(varible); getsym
end else error(4) //不是標志符,報4號錯
end {vardeclaration};

procere listcode;
var i: integer;
begin {list code generated for this block}
for i := cx0 to cx-1 do
with code[i] do
writeln(i:5, mnemonic[f]:5, 1:3, a:5)
end {listcode};

procere statement(fsys: symset);
var i, cx1, cx2: integer;
procere expression(fsys: symset); //表達式分析
var addop: symbol;
procere term(fsys: symset); //項分析
var mulop: symbol;
procere factor(fsys: symset); //因子分析
var i: integer;
begin test(facbegsys, fsys, 24); //讀入的是「(」,標志符或數字
while sym in facbegsys do
begin
if sym = ident then //是標志符,查表
begin i:= position(id);
if i = 0 then error(11) else //未找到,報11號錯
with table[i] do //找到,讀入標志符類型
case kind of
constant: gen(lit, 0, val); //寫常量命令
varible: gen(lod, lev-level, adr);//寫變數命令
proc: error(21) //過程名,報21號錯
end;
getsym //讀入下一個TOKEN
end else
if sym = number then //讀入的是數字
begin if num > amax then //如果數字大於最大數,報30號錯誤
begin error(30); num := 0
end;
gen(lit, 0, num); getsym //調用數字命令,讀入下一個TOKEN
end else
if sym = lparen then //讀入的是「(」
begin getsym; expression([rparen]+fsys); //調用表達式分析函數
if sym = rparen then getsym else error(22) //如果「(」後無「)」,報22號錯
end;
test(fsys, [lparen], 23)
end
end {factor};//因子分析結束

//項分析
begin {term} factor(fsys+[times, slash]); //調用因子分析程序
while sym in [times, slash] do //取得是乘、除號循環
begin mulop:=sym;getsym;factor(fsys+[times,slash]); //記錄符號,調用因子分析
if mulop=times then gen(opr,0,4) else gen(opr,0,5) //寫乘除指令
end
end {term};
begin {expression}
if sym in [plus, minus] then //如果是加減號
begin addop := sym; getsym; term(fsys+[plus,minus]); //記錄符號,調用項分析程序
if addop = minus then gen(opr, 0,1) //寫加減指令
end else term(fsys+[plus, minus]);
while sym in [plus, minus] do //如果是加減號循環
begin addop := sym; getsym; term(fsys+[plus,minus]);
if addop=plus then gen(opr,0,2) else gen(opr,0,3)
end
end {expression};

//條件過程
procere condition(fsys: symset);
var relop: symbol;
begin
if sym = oddsym then //如果是判奇符
begin getsym; expression(fsys); gen(opr, 0, 6) //取下一個TOKEN,調用expression,填指令
end else
begin expression([eql, neq, lss, gtr, leq, geq]+fsys);
if not(sym in [eql, neq, lss, leq, gtr, geq]) then //如果不是取到邏輯判斷符號,出錯.20
error(20) else
begin relop := sym; getsym; expression(fsys);
case relop of
eql: gen(opr, 0, 8); // =,相等
neq: gen(opr, 0, 9); // #,不相等
lss: gen(opr, 0, 10); // <,小於
geq: gen(opr, 0, 11); // ],大於等於
gtr: gen(opr, 0, 12); // >,大於
leq: gen(opr, 0, 13); // [,小於等於
end
end
end
end {condition};

begin {statement}
if sym = ident then //如果是標識符
begin i := position(id); //查找符號表
if i = 0 then error(11) else //未找到,標識符未定義,報11號錯
if table[i].kind <> varible then //如果標識符不是變數,報12號錯
begin {assignment to non-varible} error(12); i := 0
end;
getsym; if sym = becomes then getsym else error(13); //如果是變數讀入下一個TOKEN,不是賦值號,報13好錯;是則讀入一個TOKEN
expression(fsys); //調用表達是過程
if i <> 0 then //寫指令
with table[i] do gen(sto, lev-level, adr)
end else
if sym = callsym then //如果是過程調用保留字,讀入下一個TOKEN
begin getsym;
if sym <> ident then error(14) else //不是標識符報14號錯
begin i := position(id);
if i = 0 then error(11) else //是標識符,未定義,報13號錯
with table[i] do // 已定義的標識符讀入類型
if kind=proc then gen(cal, lev-level, adr) //是過程名寫指令
else error(15); //不是過程名,報15號錯
getsym
end
end else
if sym = ifsym then //如果是IF
begin getsym; condition([thensym, dosym]+fsys); //讀入一個TOKEN,調用條件判斷過程
if sym = thensym then getsym else error(16); //如果是THEN,讀入一個TOKEN,不是,報16號錯
cx1 := cx; gen(jpc, 0, 0); //寫指令
statement(fsys); code[cx1].a := cx
end else
if sym = beginsym then //如果是BEGIN
begin getsym; statement([semicolon, endsym]+fsys); //讀入一個TOKEN
while sym in [semicolon]+statbegsys do
begin
if sym = semicolon then getsym else error(10); //如果讀入的是分號
statement([semicolon, endsym]+fsys)
end;
if sym = endsym then getsym else error(17) //如果是END 讀入一個TOKEN,不是,報17號錯
end else
if sym = whilesym then //如果是WHILE
begin cx1 := cx; getsym; condition([dosym]+fsys); //調用條件過程
cx2 := cx; gen(jpc, 0, 0); //寫指令
if sym = dosym then getsym else error(18); //如果是DO讀入下一個TOKEN,不是報18號錯
statement(fsys); gen(jmp, 0, cx1); code[cx2].a := cx
end;
test(fsys, [], 19)
end {statement};

begin {block}
dx:=3;
tx0:=tx;
table[tx].adr:=cx;
gen(jmp,0,0);
if lev > levmax then error(32);
repeat
if sym = constsym then //如果是CONST
begin getsym; //讀入TOKEN
repeat constdeclaration; //常量聲明
while sym = comma do
begin getsym; constdeclaration
end;
if sym = semicolon then getsym else error(5) //如果是分號讀入下一個TOKEN,不是報5號錯
until sym <> ident //不是標志符常量聲明結束
end;
if sym = varsym then 如果是VAR
begin getsym; 讀入下一個TOKEN
repeat vardeclaration; //變數聲明
while sym = comma do
begin getsym; vardeclaration
end;
if sym = semicolon then getsym else error(5) //如果是分號讀入下一個TOKEN,不是報5號錯
until sym <> ident; //不是標志符常量聲明結束
end;
while sym = procsym do //過程聲明
begin getsym;
if sym = ident then
begin enter(proc); getsym
end
else error(4); //不是標志符報4號錯
if sym = semicolon then getsym else error(5); //如果是分號讀入下一個TOKEN,不是報5號錯
block(lev+1, tx, [semicolon]+fsys);
if sym = semicolon then //如果是分號,取下一個TOKEN,不是報5號錯
begin getsym;test(statbegsys+[ident,procsym],fsys,6)
end
else error(5)
end;
test(statbegsys+[ident], declbegsys, 7)
until not(sym in declbegsys); //取到的不是const var proc結束
code[table[tx0].adr].a := cx;
with table[tx0] do
begin adr := cx; {start adr of code}
end;
cx0 := 0{cx}; gen(int, 0, dx);
statement([semicolon, endsym]+fsys);
gen(opr, 0, 0); {return}
test(fsys, [], 8);
listcode;
end {block};

7. 編譯原理實驗報告

#include<stdio.h>
void main()
{

int m=0,n=0,n1=0,n2=0,n3=0,zg,fzg,flag;
int bz[7]=;/*狀態改變控制,1 表示可以改變狀態zt值,0 表示不可以*/
int zt[7]=;/*狀態值,2表示未定狀態,1表示 是,0表示 否*/

char temp[100]="\0";/*用於求first集*/
char z[7];/*非總結符*/
char z1[7];/*總結符*/
char z2[7]="\0";/*gs[]文法中出現的標記個數的輔助字元 01234*/
char gs[100]="\0";/*文法,按順序排成字元串*/

printf("請依次輸入非終結符(不超過7個):");
gets(z);
while(z[m]!='\0')

fzg=m;//zg是非終結符個數

while(n<m)
//生成01234輔助字元
printf("您輸入了:");
puts(z);
fflush(stdin);

printf("請依次輸入終結符(不超過7個):");
gets(z1);
while(z1[n1]!='\0')

zg=n1;
printf("您輸入了:");
puts(z1);
fflush(stdin);

printf("按照正確格式輸入所有文法(總長度不超過100格式如下):");
printf("如果文法為(字元'k'表示空):\n");
printf("S-->AB S-->bC A-->k A-->b\n");
printf("輸入:0SAB0SbC1Ak1Ab\n");
printf(" (注:數字01234表示第一二三四個非終結符)\n");

gets(gs);
fflush(stdin);
printf("您輸入了:");
puts(gs);
m=0;
//對於輸入文法字元串的轉換,將每個文法式左部去除
while(gs[m]!='\0')
{
n=m;
if(gs[m]>='0'&&gs[m]<='9')
{
m++;
while(gs[m]!='\0')
{
gs[m]=gs[m+1];
m++;
}
//gs[m-1]='\0';
}
m=++n;
}

m=0;

//puts(gs);

/*情況一,直接判定是 形如: (A-->k) */
while(gs[m]!='\0')
{
if(gs[m]=='k')
{
zt[gs[m-1]-48]=1;
bz[gs[m-1]-48]=0;
}
m++;
}

/*情況二,直接判定--否 形如: (D-->aS ,D-->c) */
for(n=0;n<fzg;n++)
{
if(bz[n]==1)
{
m=0;
n2=0;
while(gs[m]!='\0')
{
if(z2[n]==gs[m])
{
if(gs[m+1]>=z1[0]&&gs[m+1]<=z1[n1-1])
zt[n]=0;
else //gs[m+1] 是非終結符n2做標記
}
//跳出循環,無法解決該情況,推到下面情況三
m++;
}
if(n2!=99) //完成所有掃描,未出現非終結符,得出結論zt[n]=0.bz[n]=0不允許再改變zt[n]
}
}

/*情況三,最終判定*/
do
{
flag=0;
for(n=0;n<fzg;n++)
{
if(bz[n]==1) //未得到判定
{ m=0;
while(gs[m]!='\0')
{
if(gs[m]==z2[n]) //判定gs[m]是輔助字元0123
{
m++;
while(gs[m]>='A'&&gs[m]<='Z')
{

n1=0;
for(n2=0;n2<fzg;n2++) //循環查找是gs[m]哪個非終結符
{
if(gs[m]==z[n2])
{
if(zt[n2]==1) //這個非終結符能推出空
zt[n]=1;
else if(bz[n2]==1) //這個非終結符 現在 不能推出空,但它的狀態可改即它最終結果還未判定

else
//設 m1 做標記供下一if參考
break; //找到gs[m]是哪個非終結符,for循環完成任務,可以結束
}

}
if(n1==99) break;
m++;
}
}
m++;
}
if(zt[n]==1) bz[n]=0;
if(bz[n]==0) flag=1;//對應for下的第一個if(zt[n]==2)
}

}
}while(flag);

printf("結果是:\n");

for(m=0;m<5;m++)
{
switch(zt[m])
{
case 0:printf("%c---否\n",z[m]);break;
case 1:printf("%c---是\n",z[m]);break;
case 2:printf("%c---未定\n",z[m]);break;
}

}
/*
puts(gs);
puts(zt);
puts(z);
puts(z1);
puts(z2);
printf("%d,,,%d",fzg,zg);
*/

//下面求first集
//下面求first集

for(n=0;n<fzg;n++)

m=0;n=0;n1=0;n2=0;
while(gs[n]>='0'&&gs[n]<='9')
{
for(;m<fzg;m++)
{
if(n2!=m)
n1=0; //m=n2用於第二次以後的for循環中還原上次m的值

if(gs[n]==z2[m])
{
while(gs[n+1]>'9')
{
if(n1==0)
//如果是第一個直接保存

//不是第一個,先與字元數組中其它字元比較,沒相同的才保存
else if(gs[n]>='a'&&gs[n]<='z'&&gs[n+1]>='A'&&gs[n+1]<='Z') //gs[n]是終結符 且 gs[n+1]是非終結符
;//什麼也不做,程序繼續n++,掃描下一個gs[n]

else
{
for(n3=0;n3<=n1;n3++)
{
if(temp[m*13+n3]==gs[n+1])
break;
}

if(n3>n1) //for循環結束是因為n3而不是break

}
n++;
}
break; //break位於if(gs[n]==z2[m]),對於gs[n]已找到z2[m]完成任務跳出for循環
}
}
n2=m; //存放該for循環中m的值
n++;
}
//進一步處理集除去非終結符
m=0;n=0;n1=0;n2=0;
for(m=0;m<fzg;m++)
{
if(flag!=m)
n1=0; //m=flag用於第二次以後的for循環中還原上次m的值

while(temp[m*13+n1]!='\0')
{
while(temp[m*13+n1]>='A'&&temp[m*13+n1]<='Z') //搜索非終結符
{
for(n=0;n<fzg;n++) //確定是哪個非終結符
{if(temp[m*13+n1]==z[n])
break;
}
while(temp[m*13+n1]!='\0') //從temp[n*13+n1]開始每個字元依次往前移動一

n1--;
while(temp[n*13+n2]!='\0') //把z[n]對應的first加入temp[m*13+n1]這個first中,每個字元依次加在最後
{
for(n3=0;n3<n1;n3++) //循環判定是否有相同的字元
{
if(temp[m*13+n3]==temp[n*13+n2])
break;
}
if(temp[n*13+n2]=='k'&&zt[m]==0) //那些不能推出 空,但是因為要加入 其他非終結符的first集 而可能含有 空
n2++;
else if(n3>=n1) //for循環結束是因為n3而不是break ,即無相同字元

else n2++;
}

n1=0;
n2=0;
}

n1++;
}
flag=m; //存放該for循環中m的值
}

//非終結符的first集輸出
m=0;n1=0;
for(m=0;m<fzg;m++)
{
n1=0;
printf("非終結符 %c 的first集是: ",z[m]);
while(temp[m*13+n1]!='\0')
{
printf("%c",temp[m*13+n1]);
n1++;
}
printf("\n");
}

}

8. 有人知道編譯原理實驗之詞法分析器用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

9. 學完編譯原理這門課,用c語言或者c++語言,編一個預測分析的程序,對預測分析也至少測試三個句子(含錯誤

我寫好的.
scan.h

/*
* scan.h
* ccompiler
*
* Created by on 09-10-12.
* Copyright 2009 __MyCompanyName__. All rights reserved.
*
*/

#ifndef _SCAN_H_
#define _SCAN_H_

#include <string>
#include <fstream>
using namespace std;

typedef enum
{
ENDFILE,ERROR,
ELSE,IF,INT,RETURN,VOID,WHILE,
ID,NUM,
ASSIGN,EQ,LT,GT,LE,GE,NE,ADD,SUB,MUL,DIV,SEMI,LPAREN,RPAREN,LZK,RZK,LDK,RDK,COMMA
}
TokenType;

class Scan
{
private:
string tokenStr;
string linebuffer;
ifstream * in;
int linepos;
int lineno;
bool EOF_Flag;
bool traceScan;
void printToken(TokenType tt,const string &tok);
public:
Scan(ifstream * in)
{
this->in=in;
linepos=0;
linebuffer="";
lineno=0;
EOF_Flag=false
traceScan=true;
}
char getNextChar();

void ungetNextChar();

TokenType reservedLookup(string &s);

void setTraceScan(bool f);

bool getTraceScan();

TokenType getToken();

string getTokenStr();

};
#endif

scan.cpp

/*
* scan.cpp
* ccompiler
*
* Created by on 09-10-12.
* Copyright 2009 __MyCompanyName__. All rights reserved.
*
*/

#include <string>
#include <fstream>
#include <iostream>
using namespace std;

#include "scan.h"

typedef enum

StateType;

static struct
{
string str;
TokenType tok;
} reservedWords[6]
=,,,,,};

char Scan::getNextChar()
{
if(linepos>=linebuffer.size())
{
if(getline(*in,linebuffer))
{
linebuffer+="\n";
lineno++;
linepos=0;
return linebuffer[linepos++];
}
else
{
EOF_Flag=true;
return EOF;
}
}
else
return linebuffer[linepos++];
}

void Scan::ungetNextChar()
{
if(!EOF_Flag) linepos--;
}

TokenType Scan::reservedLookup(string &s)
{
for(int i=0;i<6;i++)
if(s==reservedWords[i].str)
return reservedWords[i].tok;
return ID;
}

void Scan::setTraceScan(bool f)
{
traceScan=f;
}

bool Scan::getTraceScan()
{
return traceScan;
}

TokenType Scan::getToken()
{
tokenStr="";
TokenType currentToken;
StateType state=START;

while(state!=DONE)
{
bool save=false;
char c=getNextChar();
switch (state) {
case START:
if(c>='0'&&c<='9'){
state=INNUM;
save=true;
}
else if((c>='a'&&c<='z')||(c>='A'&&c<='Z')){
state=INID;
save=true;
}
else if(c==' '||c=='\t'||c=='\n')
{
state=START;
}
else if(c=='/'){
state=SLASH;
}
else if(c=='='){
state=TEMPE;
}
else if(c=='>')
state=TEMPG;
else if(c=='<')
state=TEMPL;
else if(c=='!')
state=INNOTEQ;
else
{
state=DONE;
switch (c) {
case EOF:
currentToken=ENDFILE;
break;
case '+':
currentToken=ADD;
break;
case '-':
currentToken=SUB;
break;
case '*':
currentToken=MUL;
break;
case '(':
currentToken=LPAREN;
break;
case ')':
currentToken=RPAREN;
break;
case '[':
currentToken=LZK;
break;
case ']':
currentToken=RZK;
break;
case '{':
currentToken=LDK;
break;
case '}':
currentToken=RDK;
break;
case ';':
currentToken=SEMI;
break;
case ',':
currentToken=COMMA;
break;
default:
currentToken=ERROR;
break;
}
}
break;
case INNUM:
if(c<'0'||c>'9')
{
ungetNextChar();
state=DONE;
currentToken=NUM;
}
else
save=true;
break;
case INID:
if(!((c>='a'&&c<='z')||(c>='A'&&c<='Z')))
{
ungetNextChar();
state=DONE;
currentToken=ID;
}
else
save=true;
break;
case SLASH:
if (c!='*')
{
state=DONE;
currentToken=DIV;
}
else
state=INCOMMENT1;
break;
case INCOMMENT1:
if (c!='*')
state=INCOMMENT1;
else if(c==EOF){
state=DONE;
currentToken=ENDFILE;
}
else
state=INCOMMENT2;
break;
case INCOMMENT2:
if (c=='*') {
state=INCOMMENT2;
}else if(c=='/'){
state=START;
}else if(c==EOF){
state=DONE;
currentToken=ENDFILE;
}else {
state=INCOMMENT1;
}
break;
case TEMPE:
if (c=='=') {
state=DONE;
currentToken=EQ;
}else{
state=DONE;
ungetNextChar();
currentToken=ASSIGN;
}
break;
case TEMPG:
if (c=='=') {
state=DONE;
currentToken=GE;
}else{
state=DONE;
ungetNextChar();
currentToken=GT;
}
break;
case TEMPL:
if (c=='=') {
state=DONE;
currentToken=LE;
}else{
state=DONE;
ungetNextChar();
currentToken=LT;
}
break;
case INNOTEQ:
if (c=='=') {
state=DONE;
currentToken=NE;
}else {
state=DONE;
ungetNextChar();
currentToken=ERROR;
}
break;

default:
cerr<<"Scanner Bug: state= "<<state<<endl;
state=DONE;
currentToken=ERROR;
break;
}
if(save){
string newChar(1,c);
tokenStr+=newChar;
}
if (state==DONE&¤tToken==ID)
currentToken=reservedLookup(tokenStr);
}
if (traceScan) {
cout<<"Scan at line "<<lineno<<" token: ";
printToken(currentToken, tokenStr);
cout<<endl;
}
return currentToken;
}

string Scan::getTokenStr()
{
return tokenStr;
}

void Scan::printToken(TokenType tt,const string &tok)
{
string type;
switch (tt) {
case ENDFILE:
type="EOF";
break;
case ERROR:
type="ERROR";
break;
case ELSE:
case IF:
case INT:
case RETURN:
case VOID:
case WHILE:
type="reserved word";
break;
case ID:
type="ID";
break;
case NUM:
type="NUM";
break;
case ASSIGN:
type="=";
break;
case EQ:
type="==";
break;
case LT:
type="<";
break;
case GT:
type=">";
break;
case LE:
type="<=";
break;
case GE:
type=">=";
break;
case NE:
type="!=";
break;
case ADD:
type="+";
break;
case SUB:
type="-";
break;
case MUL:
type="*";
break;
case DIV:
type="/";
break;
case SEMI:
type=";";
break;
case LPAREN:
type="(";
break;
case RPAREN:
type=")";
break;
case LZK:
type="[";
break;
case RZK:
type="]";
break;
case LDK:
type="{";
case RDK:
type="}";
break;
case COMMA:
type=",";
break;
default:
break;
}
cout << type<<": "<<tok;
}

main.cpp

#include <iostream>
#include <fstream>
#include <string>
using namespace std;
#include "scan.h"

int main (int argc, char * const argv[]) {
string fileName="/Users/huanglongyin/scan_in.txt";
//cout<< "File name: ";
//cin>>fileName;
ifstream in(fileName.c_str());
if(!in){
cerr<<"Error occurs when openning file "<<fileName<<endl;
return -1;
}
Scan scan(&in);
while(scan.getToken()!=ENDFILE);
return 0;
}

閱讀全文

與編譯原理實驗測試程序相關的資料

熱點內容
dvd光碟存儲漢子演算法 瀏覽:757
蘋果郵件無法連接伺服器地址 瀏覽:963
phpffmpeg轉碼 瀏覽:671
長沙好玩的解壓項目 瀏覽:145
專屬學情分析報告是什麼app 瀏覽:564
php工程部署 瀏覽:833
android全屏透明 瀏覽:737
阿里雲伺服器已開通怎麼辦 瀏覽:803
光遇為什麼登錄時伺服器已滿 瀏覽:302
PDF分析 瀏覽:485
h3c光纖全工半全工設置命令 瀏覽:143
公司法pdf下載 瀏覽:382
linuxmarkdown 瀏覽:350
華為手機怎麼多選文件夾 瀏覽:683
如何取消命令方塊指令 瀏覽:349
風翼app為什麼進不去了 瀏覽:778
im4java壓縮圖片 瀏覽:362
數據查詢網站源碼 瀏覽:150
伊克塞爾文檔怎麼進行加密 瀏覽:892
app轉賬是什麼 瀏覽:163