有了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)

 4 33      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;
}

是不是很简单?


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值