簡體   English   中英

如何編寫上下文無關文法?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM