Solution
解答
view sourceprint?01 #include <iostream>
02 #include <string>
03 #include <vector>
04 using namespace std;
05 //各種符號的枚舉,后面的注釋為題目中對應(yīng)的符號
06 enum SYMBOL{A, MOD, LA, BA, DA, PREDA, NAM, SE, PC, P, PN, PS, ST, VP, PV, UN};
07 bool aVowel[] = {1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0}; //元音表
08 static SYMBOL aConvTbl[14][4] = { //狀態(tài)轉(zhuǎn)換表
09 {PREDA, UN, PREDA, PREDA}, {PREDA, UN, UN, PS}, {NAM, UN, UN, PN},
10 {LA, UN, PS, PN}, {MOD, UN, PS, VP}, {A, PS, PS, PS}, {PS, UN, UN, P},
11 {DA, UN, P, PC}, {BA, PN, P, PC}, {VP, PN, UN, PV}, {PV, UN, PN, ST},
12 {PV, UN, UN, ST}, {PC, UN, UN, SE}, {ST, UN, UN, SE},
13 };
14 //判斷是否元音字母的函數(shù)
15 inline bool isvowel(char c) {
16 return islower(c) && aVowel[c - 'a'];
17 }
18 //將輸入的字符串轉(zhuǎn)為狀態(tài)
19 SYMBOL Token2Status(const string &str) {
20 int nNum = str.length();
21 if (!isvowel(str[nNum - 1])) {
22 return NAM; //末尾不是元音的為NAM
23 }
24 switch (nNum) {
25 case 1: return A; //只有一位元音的只能是A
26 case 5: //用位運算快速判斷謂詞是否符合規(guī)則CCVCV或CVCCV
27 nNum = isvowel(str[4]);
28 nNum |= ((isvowel(str[0]) << 4) | (isvowel(str[1]) << 3));
29 nNum |= ((isvowel(str[2]) << 2) | (isvowel(str[3]) << 1));
30 return (nNum == 5 || nNum == 9) ? PREDA : UN;
31 case 2: //兩位的單詞
32 switch (str[0]) { //根據(jù)第一位判斷是哪一組
33 case 'g': return MOD;
34 case 'b': return BA;
35 case 'd': return DA;
36 case 'l': return LA;
37 }
38 }
39 return UN; //未能識別的錯誤符號
40 }
41 //詞法分析函數(shù),算法過程詳見相關(guān)文檔
42 bool ParseSentence(vector<SYMBOL> &Set) {
43 for (int i = 0; i < 14; ++i) { //依次處理每一種狀態(tài)
44 SYMBOL *pTbl = aConvTbl[i]; //為加快運算,節(jié)省代碼,設(shè)臨時變量
45 for (vector<SYMBOL>::iterator j = Set.begin(); j != Set.end();) {
46 if (*j != pTbl[0]) {
47 ++j; //不是指定符號,遍例下一個
48 continue;
49 } //如果指定了前面或后面相鄰的符號則驗證其是否存在
50 if (pTbl[1] != UN && (j == Set.begin() || *(j - 1) != pTbl[1])) {
51 ++j; //存在的符號與指定的不符,結(jié)果錯誤
52 continue;
53 }
54 if (pTbl[2] != UN && (j == Set.end() - 1 || *(j + 1) != pTbl[2])) {
55 ++j; //存在的符號與指定的不符,結(jié)果錯誤
56 continue;
57 } //刪除前后的符號(如果指定)
58 j = pTbl[1] != UN ? Set.erase(j - 1) : j;
59 j = pTbl[2] != UN ? Set.erase(j + 1) - 1 : j;
60 *j = pTbl[3]; //當(dāng)前符號變更為指定的目標(biāo)符號
61 }
62 }
63 return (Set.size() == 1 && Set.front() == SE); //返回結(jié)果
64 }
65 //主函數(shù)
66 int main(void) {
67 vector<SYMBOL> Set;
68 for (string str; cin >> str && str != "#";) { //循環(huán)讀入每個單詞
69 int nDot = str.find('.'); //如果單詞中發(fā)現(xiàn)句點,則認(rèn)為句子結(jié)束
70 if (nDot == str.npos) { //沒有發(fā)現(xiàn)句點
71 Set.push_back(Token2Status(str)); //將單詞轉(zhuǎn)為符號后存入語句
72 continue;
73 } //以下為發(fā)現(xiàn)句點,即遇到句子結(jié)束
74 str.erase(str.length() - 1); //刪除句點
75 if (!str.empty()) { //單詞不為空則加入語句
76 Set.push_back(Token2Status(str));
77 } //以下進(jìn)行詞法分析并輸出結(jié)果
78 cout << (ParseSentence(Set) ? "Good" : "Bad!") << endl;
79 Set.clear(); //清空語句,準(zhǔn)備處理下一條語句
80 }
81 return 0;
82 }<BR>
本文導(dǎo)航
- 第1頁: 首頁
- 第2頁: Loglan 語言分析
- 第3頁: 下面是處理好的正則文法
- 第4頁: Loglan問題解決方案