第一章 如何用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++的跳转进行状态维护的。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)
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呢?
因为它为了避免和 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的语法树。{
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 语法树如何遍历
下面代码简单的递归就可以遍历整棵树了。
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才有效,一般用在符号的语法点。{
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是这样写的
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 ++ ;
}
}
{
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;
}
{
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;
}
是不是很简单?