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 ...
...
請注意:以上所有是相當簡單的,可能包含錯誤!但基本上它是如何工作的,它不是那複雜,它只是有一些你必須學習的花式名稱。
剛纔看到馬爾科姆麥克萊恩的回答被認爲是可以接受的,所以...