有了DD,還會有人用LEX & YACC?

第一章 如何用DD設計詞法分析器
用 DD 打開 xml.ddw,第一個 diagram 看到的就是詞法分析器的定義,其中定義了各種數據類型(integer,float,string),定義了indentifier,定義了c++應該有的操作符。

第一節 可視化定義
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         }
其中s101的跳轉,正是圖中s101狀態,原來,這段程序都是利用C++的跳轉進行狀態維護的。

第二章 如何定義語法
第一節 認識圖中用到的元件

元件有:總開始,節點開始,節點結束,常數,節點,標識,關鍵字,數字,符號,狀態等。< 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_pass來對lookup right(LR)是否成功的判斷,只要{}的深度繼續,LR(n),n要多大都沒有問題。產生LR(n)需要下面的一個設置

那爲什麼需要lookup right呢?
因爲它爲了避免和 TAG 的頭衝突 ,所以要往右邊多看一個字符,就是看是不是有'/',如果有,則認爲是 TAG結束,否則是下一層 TAG :


第三章 如何使用所生成的代碼
1 請參看main.cpp的main函數
int main(int argc, char* argv[])
{
    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;
}
首先用f.LoadFile(file_name,true);進行內容裝入,並且進行預處理;然後l.Compile(f.GetSourceCode());進行詞法分析;接着p.Parse(&l.Words);就是語法分析。最後得到p.GrammarTree的語法樹。

2 語法樹如何遍歷
下面代碼簡單的遞歸就可以遍歷整棵樹了。
void PrintGrammaTree(LGrammarTree *tree,LWideString &ret)
{
    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);
        }
    }
}
如果再加上對theTree->Node->Type或者theTree->Node->ExtType的判斷就能做語義分析了。注:theTree->Node->Type爲sxtNone的時候theTree->Node->ExtTyp纔有效,一般用在符號的語法點。

如果到此還不是很清楚如何遍歷語法樹的話,再看看一個 XML Reader的源代碼會更清楚(這裏下載全部源代碼XmlParser.zip)
  i 讀TAG是這樣寫的
static void ReadTag(LGrammarTree *pGrammarTree,tagXmlTree *pXmlTree)
{
    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 而讀入屬性是這樣寫的
static void ReadAttributes(LGrammarTree *pGrammarTree,StringProperties &pProperties)
{
  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;
}

是不是很簡單?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章