[英]How to program a context-free grammar?
我這里有兩節課。
CFG 類在其構造函數中采用一個字符串數組來定義上下文無關文法。 SampleTest 類用於測試 CFG 類,方法是將語法 (C) 輸入到類中,然后由用戶輸入一個字符串,然后查看該字符串是否可以由上下文無關語法生成。
我遇到的問題是堆棧溢出(顯然)。 我假設我剛剛創建了一個永無止境的遞歸函數。
有人可以看看 processData() 函數,並幫助我弄清楚如何正確配置它。 我基本上使用遞歸來生成 CFG 可以創建的字符串的所有可能性,然后如果生成的這些可能性之一與用戶的輸入 (inString) 匹配,則返回 true。 哦,wkString 參數只是語法通過每次遞歸迭代生成的字符串。
public class SampleTest {
public static void main(String[] args) {
// Language: strings that contain 0+ b's, followed by 2+ a's,
// followed by 1 b, and ending with 2+ a's.
String[] C = { "S=>bS", "S=>aaT", "T=>aT", "T=>bU", "U=>Ua", "U=>aa" };
String inString, startWkString;
boolean accept1;
CFG CFG1 = new CFG(C);
if (args.length >= 1) {
// Input string is command line parameter
inString = args[0];
char[] startNonTerm = new char[1];
startNonTerm[0] = CFG1.getStartNT();
startWkString = new String(startNonTerm);
accept1 = CFG1.processData(inString, startWkString);
System.out.println(" Accept String? " + accept1);
}
} // end main
} // end class
public class CFG {
private String[] code;
private char startNT;
CFG(String[] c) {
this.code = c;
setStartNT(c[0].charAt(0));
}
void setStartNT(char startNT) {
this.startNT = startNT;
}
char getStartNT() {
return this.startNT;
}
boolean processData(String inString, String wkString) {
if (inString.equals(wkString)) {
return true;
} else if (wkString.length() > inString.length()) {
return false;
}
// search for non-terminal in the working string
boolean containsNT = false;
for (int i = 0; i < wkString.length(); i++) {
// if one of the characters in the working string is a non-terminal
if (Character.isUpperCase(wkString.charAt(i))) {
// mark containsNT as true, and exit the for loop
containsNT = true;
break;
}
}
// if there isn't a non-terminal in the working string
if (containsNT == false) {
return false;
}
// for each production rule
for (int i = 0; i < this.code.length; i++) {
// for each character on the RHS of the production rule
for (int j = 0; j <= this.code[i].length() - 3; j++) {
if (Character.isUpperCase(this.code[i].charAt(j))) {
// make substitution for non-terminal, creating a new working string
String newWk = wkString.replaceFirst(Character.toString(this.code[i].charAt(0)), this.code[i].substring(3));
if (processData(inString, newWk) == true) {
return true;
}
}
}
} // end for loop
return false;
} // end processData
} // end class
您的語法包含左遞歸規則
U=>Ua
正如您剛剛發現的那樣,遞歸下降解析器無法處理左遞歸。
你有兩個選擇:改變你的語法不再是左遞歸,或者使用可以處理它的解析算法,比如 LR1。 在您的情況下, U
匹配“至少兩個a
字符”,因此我們可以將遞歸向右移動。
U=>aU
一切都會好起來的。 這並不總是可以以如此好的方式完成,但在您的情況下,避免左遞歸是簡單的解決方案。
你不需要這個 for 循環:“for (int j = 0; j <= this.code[i].length() - 3; j++)”。 只需創建一個 var 來保存您在上面所做的非終結符搜索中的大寫字母。 然后做你的外部 for 循環,然后如果 String[] 中有一個以找到的非終端開頭的生產規則,做你的替換和遞歸。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.