Để dựng được cây phân tích, bao giờ ta cũng cần tìm dẫn xuất trái của quá trình phân tích. Dẫn xuất trái là một dẫn xuất tại mỗi bước luôn luôn chọn chữ phụ đầu tiên của xâu trung gian để thực hiện phép thế. Như vậy, một xâu ω bất kỳ thuộc vào ngôn ngữ sinh bởi văn phạm G khi và chỉ khi có tồn tại dẫn xuất trái để từ ký hiệu khởi đầu S suy dẫn được ra ω. Ta gọi dãy các số hiệu của các quy tắc suy dẫn i1i2...in là dãy trái. Ta quy bài toán phân tích câu về bài toán tìm dãy trái của ω.
Với những cấu trúc dữ liệu và thuật toán đã trình bày, ta có phương thức tìm dãy trái của một xâu như sau:
¾ Input: Một câu tiếng Anh ω, các từ cách nhau ít nhất một ký tự trắng, không có các dấu chấm câu
¾ Output: Dãy trái của ω nếu phân tích được, hoặc trả lời không đoán nhận được
public Vector parse(String w) { int i,j;
boolean recognizable = false; // đã đoán nhận được?
Vector parsingOrder = new Vector();// dãy trái của phân tích // Lấy ra các từ trong câu
StringTokenizer stk = new StringTokenizer(w); int n = stk.countTokens();
tokens = new String[n]; i = 0;
while (stk.hasMoreTokens()) { tokens[i] = stk.nextToken(); i++;
}
String curState = ""; // trạng thái hiện tại
int curPos = 0; // vị trí hiện tại
Stack backupStates = new Stack(); // các trạng thái sao lưu
Stack positions = new Stack(); // các vị trí sao lưu
Stack ruleIdxs = new Stack(); // chỉ số các quy tắc được chọn
backupStates.push(startSymbol); // startSymbol = S - câu
ruleIdxs.push(new Vector()); positions.push(new Integer(0));
// vòng lặp phân tích
while ((!backupStates.isEmpty()) && (!recognizable)) { curState = (String)backupStates.pop();
parsingOrder = (Vector)ruleIdxs.pop();
curPos = ((Integer)positions.pop()).intValue(); j = 0;
while ((curState.length() > 0) &&
(Character.isLowerCase(curState.charAt(j)))) {
// lo•i b• nh•ng ph••ng án không th• ••a t•i k•t qu•… while ((curState.length() > n-curPos) &&
(!backupStates.isEmpty())) { curState = (String)backupStates.pop(); curPos = ((Integer)positions.pop()).intValue(); parsingOrder = (Vector)ruleIdxs.pop(); } // nếu từ hiện tại thuộc kiểu từ loại này…
curState = (curState.length() == 1)? "" : curState.substring(1);
j = 0;
if ((curPos >= tokens.length) && curState.compareTo("") == 0)){ recognizable = true;
break; }
} else { // n•u không thì xét v• trí và tr•ng thái sao l•u… if (!positions.isEmpty()) curPos = ((Integer)positions.pop()).intValue(); if (!backupStates.isEmpty()) { curState = (String)backupStates.pop(); parsingOrder = (Vector)ruleIdxs.pop(); } else break; } }
// Áp d•ng các suy d•n: ••a các ph••ng án ti•p theo vào các ng•n x•p, // ch• ••a vào các ph••ng án có kh• n•ng cho k•t qu•
if ((!recognizable) && (curState.compareTo("") != 0)) for (i = 0; i < numberOfRules; i++)
if ((left[i].compareTo("" + curState.charAt(0)) == 0) && (curState.length() <= tokens.length-curPos+1)) { backupStates.push(right[i]+
((curState.length() >= 1) ? curState.substring(1) : ""));
positions.push(new Integer(curPos)); Vector tempVec = new Vector();
for (Enumeration e = parsingOrder.elements(); e.hasMoreElements();)
tempVec.addElement((Integer)e.nextElement()); tempVec.addElement(new Integer(i+1));
ruleIdxs.push(tempVec); }
} // kết thúc vòng lặp phân tích
if (!recognizable) return new Vector(); else return parsingOrder;
}
Phương thức parse nêu trên tìm dãy trái của ω và đưa nó vào một vector các số nguyên, mỗi phần tử của vector này là số hiệu của các quy tắc suy dẫn tương ứng.