2016-10-02 154 views
-2

我必須爲標識符和數字的詞法分析器創建轉換圖。如何基於C代碼創建轉換圖

的代碼包含如下:

/* recursive factorial function */ 
int fact (int x) 
{ 
    if (x>1) 
     return x * fact (x-1); 
    else 
     return 1; 
} 

void main (void) 
{ 
    int x;  
    x = read(); 
    if (x > 0) write (fact (x)); 
} 

我感覺如何創建這個圖有點失落。任何人都可以用正確的方向指出我的意思,或者包括可以幫助我完成這項任務的資源?

回答

0

詞法分析器從零或初始狀態開始。它擊中了「我」。所以它知道它必須有關鍵字或標識符。它擊中'n'和't'並將它們添加到令牌中。它擊中了空間。所以它知道這是令牌的結尾,它是一個關鍵字「int」。現在它擊中'f'。同樣的故事,但令牌是「事實」,這不是關鍵字,所以它是一個標識符。現在,'(' - 這是一個開放的括號令牌,所以它繼續下去

當它碰到'/'可能是除法令牌或評論的開始,實際上它是評論的開始。所以它現在進入註釋狀態直到碰到* /。

除了你有幾個整數文字標記外,沒有別的區別了,爲了方便你,沒有字符串。是有點特殊的情況下,取決於如何編寫詞法分析器,它可以被視爲關鍵字或明確的標識符。

0

Malcolm McLean告訴你如何在實際的代碼中做到這一點,但我認爲你需要更多的理論具有有限屬性的方法e機器。

首先做一個盤點:需要什麼,什麼符號做我們從示例代碼等EBNF:

space = ? US-ASCII character 32 ?; 
zero = '0'; 
digit = '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'; 
character = 'a' | 'A' | 'b' | 'B' ... 'z' | 'Z'; 

(* a single digit might be zero but a number must not start with a zero (no octals) *) 
integer = (digit|zero) | (digit,{(digit|zero)}); 
(* identifier must start with a character *) 
identifier = character,{ (digit | character) }; 
(* the keywords from the example, feel free to add more *) 
keywords = "if" | "else" | "return" | "int" | "void"; 

(* TODO: line-end, tabs, etc. *) 
delimiter = space, {space}; 

braceleft = '{'; 
braceright = '}'; 
parenleft = '('; 
parenright = ')'; 

equal = '='; 
greater = '>'; 
smaller = '<'; 

minus = '-'; 
product = '*'; 

semicolon = ';' 

end = ? byte denoting EOF (end of file) ?; 

現在轉型做表。從狀態START開始。 START僅僅是開始狀態,沒什麼特別的,沒什麼可做的,但我們需要從某個地方開始。所以從那裏我們可以得到任何上述字符。事實上,在每個州之後都是這樣,所以我們可以做C&P;

START 
     zero  -> ZERO 
     digit  -> INTEGER 
     character -> IDENTIFIER 
     space  -> START 
     braceleft -> BRACES 
     braceright -> BRACES 
     parenleft -> PARENTHESES 
     parenright -> PARENTHESES 
     equal  -> COMPARING 
     greater  -> COMPARING 
     smaller  -> COMPARING 
     minus  -> ARITHMETIC 
     product  -> ARITHMETIC 
     semicolon -> START 
     end   -> END 

ZERO 
     zero  -> ERROR (well...) 
     digit  -> ERROR 
     character -> ERROR 
     space  -> START 
     braceleft -> BRACES 
     braceright -> BRACES 
     parenleft -> PARENTHESES 
     parenright -> PARENTHESES 
     equal  -> COMPARING 
     greater  -> COMPARING 
     smaller  -> COMPARING 
     minus  -> ARITHMETIC 
     product  -> ARITHMETIC 
     semicolon -> START 
     end   -> END 

INTEGER 
     zero  -> INTEGER 
     digit  -> INTEGER 
     character -> ERROR 
     space  -> START 
     braceleft -> BRACES 
     braceright -> BRACES 
     parenleft -> PARENTHESES 
     parenright -> PARENTHESES 
     equal  -> COMPARING 
     greater  -> COMPARING 
     smaller  -> COMPARING 
     minus  -> ARITHMETIC 
     product  -> ARITHMETIC 
     semicolon -> START 
     end   -> END 

狀態IDENTIFIER意味着我們已經有一個角色,所以

IDENTIFIER 
     zero  -> IDENTIFIER 
     digit  -> IDENTIFIER 
     character -> IDENTIFIER 
     space  -> START 
     braceleft -> BRACES 
     braceright -> BRACES 
     parenleft -> PARENTHESES 
     parenright -> PARENTHESES 
     equal  -> COMPARING 
     greater  -> COMPARING 
     smaller  -> COMPARING 
     minus  -> ARITHMETIC 
     product  -> ARITHMETIC 
     semicolon -> START 
     end   -> END 

沒有什麼,遵循國家ERROR除了狀態ERROR

ERROR -> ERROR 

沒有什麼,如下國家END除國家ERROR

END -> ERROR 



ARITHMETIC 
     zero  -> ZERO 
     digit  -> INTEGER 
     character -> IDENTIFIER 
     space  -> START 
     braceleft -> BRACES 
     braceright -> BRACES 
     parenleft -> PARENTHESES 
     parenright -> PARENTHESES 
     equal  -> COMPARING 
     greater  -> COMPARING 
     smaller  -> COMPARING 
     minus  -> ARITHMETIC 
     product  -> ARITHMETIC 
     semicolon -> START 
     end   -> END 

離開計數和餘額確認解析器

BRACES -> START 
PARENTHESES -> START 

COMPARING 
     zero  -> ZERO 
     digit  -> INTEGER 
     character -> IDENTIFIER 
     space  -> START 
     braceleft -> BRACES 
     braceright -> BRACES 
     parenleft -> PARENTHESES 
     parenright -> PARENTHESES 
     equal  -> ERROR (only check for single characters here, no ">=" or similar) 
     greater  -> ERROR 
     smaller  -> ERROR 
     minus  -> ERROR 
     product  -> ERROR 
     semicolon -> ERROR 
     end   -> ERROR 

在此希望我沒有實施任何嚴重的錯誤留下的唯一問題是,在空間和關鍵字。 隨着例如「如果」:

在一個字符中第一次出現

 character -> KEYWORDS 

KEYWORDS 
     'i' -> IF 
     'r' -> RETURN 
     ... 
     any other character (exc. parens etc.) -> IDENTIFIER 

IF 
     'f' -> IT_IS_IF 
     ... 
     any other character (exc. parens etc.) -> IDENTIFIER 

IT_IS_IF 
     '(' -> START 
     ')' -> ERROR 
     '=' -> ERROR 
     ... 
     digit or character -> IDENTIFIER 

您可以用快捷鍵做,當然,使每個關鍵字一個符號,這將是非常乏味的除此以外。我猜是允許一點作弊行爲?

在一個字符中第一次出現

再次

 character -> KEYWORDS 

KEYWORDS 
     if_symbol -> IF 
     else_symbol -> ELSE 
     return_symbol -> RETURN 
     ... 
     digit or character -> IDENTIFIER 

IF 
     '(' -> PARENTHESES 
     ')' -> ERROR 
     '=' -> ERROR 
     ... 

所以,可以你只是跳過所有的空白?像

return x; 

的構建是合法的是

returnx; 

所以,一旦你完全有一個關鍵字它要麼後面有一個空格(或經過一定的分號或大括號或任何符號允許重新接入的字)或後面跟隨一個字符/數字,這使得它成爲一個標識符,或者後面跟着一個不允許的東西。其餘的可以,而且應該留給解析器。

或者你採取第一擊的方法:一旦你有一個關鍵字,你回去開始,所以returnx;將被視爲RETURN IDENTIFIER SEMICOLON。但是這會減少可能的標識符的數量,例如:ifitsone將是IF ERROR,這很可能會導致您的bug列表中出現很多惱人的條目。

有了以上所有信息,您就可以構建表格。如果我們設置的行狀態和列符號

   zero  digit  character space braceleft braceright parenleft ... 
START  ZERO  INTEGER IDENTIFIER START BRACES  BRACES PARENTHESES ... 
ZERO   ERROR  ERROR  ERROR  START BRACES  BRACES PARENTHESES ... 
INTEGER  INTEGER INTEGER ERROR  START BRACES  BRACES PARENTHESES ... 
IDENTIFIER IDENTIFIER IDENTIFIER IDENTIFIER START BRACES  BRACES PARENTHESES ... 
    ... 

請注意:以上所有是相當簡單的,可能包含錯誤!但基本上它是如何工作的,它不是複雜,它只是有一些你必須學習的花式名稱。

剛纔看到馬爾科姆麥克萊恩的回答被認爲是可以接受的,所以...