第一節 可視化定義
1 先看identifier(標識符)怎麼定義:
先從黑色小圓點開始,它可以首先遇到letter(a-z大小寫字符),或者首先遇到下劃線。然後進入狀態s1,在s1狀態,它有3個去向,letter(字符)、下劃線、或者數字。如果都不是,就出來,成爲identifier(標識符)。這就是“以字母開頭,可以是字母或數字”的標識符定義。
這個定義可以參照加利福尼亞大學的圖:http://www-ccs.ucsd.edu/c/syntax.html< /span>
2 再看看數字怎麼定義
可以看到,如果是全部爲數字,則視作整數,如果存在小數點,則視作浮點。
這個定義可以參照加利福尼亞大學的圖:http://www-ccs.ucsd.edu/c/syntax.html
其他定義也一幕瞭然不再贅述。
第二節生成的代碼
通過菜單
產生代碼,看看文件Lex.cpp的GetNextWord函數
584 if(Source[CurrPos]>=L'0' && Source[CurrPos]<=L'9')
585 {
586 CurrPos++;
587 Colume++;
588 goto s101;
589
590 }
.....
643
644 s101:
645 if(Source[CurrPos]>=L'0' && Source[CurrPos]<=L'9')
646 {
647 CurrPos++;
648 Colume++;
649 goto s101;
650
651 }
元件有:總開始,節點開始,節點結束,常數,節點,標識,關鍵字,數字,符號,狀態等。< br>第二節 符號
符號是分號,都好,等號等定義,名字要和詞法定義的名字一致。
第三節狀態
狀態是一種分析狀態。在嚴格的情況下是不必的,但是對於“多入多出”的語法點,用狀態可以減少連線。
第四節節點
節點就是規式左部,要實現它的定義,用節點開始到節點結束來表示。
第五節 XML的語法定義
第六節 生成代碼
1 點擊菜單:
然後就會得到1600行左右的 Parser.cpp。其中對於XML的TAG的分析都在Is_Tag函數裏面實現。
2 所生成的代碼如何處理 LR(n)
433 S_E2E8839C55C64321BA2B03B1BEE49BA7://Tag
434 if(current_word->Type==ltLess)//'<'
435 {
436 index_1=index;
437 lookup_right_pass=false;
438 if(!lookup_right_pass)
439 {
440 index_1++;
441 if((*words)[index_1]->Type==ltDiv/*'/'*/)
442 lookup_right_pass=true;
443 index_1--;
444 }
445
446 if(lookup_right_pass)
447 {
448 AddNode(tree,sxtNone,current_word->Type,current_word->Value);
449
450 index++;
451 current_word=(*words)[index];
452 goto S_3446830BCAD449E6A9EBD0512F60EC93;//Less
453 }
454 }
那爲什麼需要lookup right呢?
因爲它爲了避免和 TAG 的頭衝突 ,所以要往右邊多看一個字符,就是看是不是有'/',如果有,則認爲是 TAG結束,否則是下一層 TAG :
{
LFileLoader f(CPP_SYNTAX);
LLex l(CPP_SYNTAX);
.......
f.LoadFile(file_name,true);
l.Compile(f.GetSourceCode());
.....
LParser p(CPP_SYNTAX);
p.Parse(&l.Words);
LWideString prints;
PrintGrammaTree(&p.GrammarTree,prints);
wprintf(prints.GetText());
return 0;
}
2 語法樹如何遍歷
下面代碼簡單的遞歸就可以遍歷整棵樹了。
{
LGrammarTree::LoopVariant begin,end;
LGrammarTree *theTree;
end=tree->Children.end();
for(begin=tree->Children.begin();begin!=end;begin++)
{
theTree=*begin;
if(theTree->Children.size()==0)
{
ret.Append(L" ");
ret.Append(theTree->Node->Value);
}else
{
ret.Append(L"/*");
ret.Append(theTree->Node->Value);
ret.Append(L"*/");
PrintGrammaTree(theTree,ret);
}
}
}
如果到此還不是很清楚如何遍歷語法樹的話,再看看一個 XML Reader的源代碼會更清楚(這裏下載全部源代碼XmlParser.zip)
i 讀入TAG是這樣寫的
{
LGrammarTree *theTree;
LGrammarTree::LoopVariant begin,end;
tagXmlTree the_xml_tree;
begin=pGrammarTree->Children.begin();
//跳過 '<'
begin++;
//到了tag名字
theTree=*begin;
PrintSyntaxTree(theTree,pXmlTree->TagName);
begin++;
end=pGrammarTree->Children.end();
while(begin!=end)
{
theTree=*begin;
if(theTree->Node->Type==sxtAttributes)
{
ReadAttributes(theTree,pXmlTree->Properties);
}else
if(theTree->Node->Type==sxtTag)
{
the_xml_tree.Children.clear();
ReadTag(theTree,&the_xml_tree);
pXmlTree->Children.push_back(the_xml_tree);
}
begin++;
}
}
ii 而讀入屬性是這樣寫的
{
LGrammarTree *theTree;
LGrammarTree::LoopVariant begin;
wchar_t *attr_name;
wchar_t *attr_value;
int len;
begin=pGrammarTree->Children.begin();
theTree=*begin;
attr_name=theTree->Node->Value.GetText();
begin++;
//跳過 '='
begin++;
theTree=*begin;
attr_value=theTree->Node->Value.GetText();
if(attr_value[0]==L'/"')
{
len=wcslen(attr_value);
if(len>1)
{
attr_value[len-1]=0;
attr_value++;
}
}
LWideString w;
w=attr_name;
pProperties[w]=attr_value;
}
是不是很簡單?