我试图在C中为XML文件构建小型解析器。我知道,我可以找到一些完成的解决方案,但是,我只需要一些基本的东西用于嵌入式项目。我试图创建语法来描述没有属性的XML,只是标签,但似乎它不起作用,我无法弄清楚原因。
这是语法:
XML : FIRST_TAG NIZ
NIZ : VAL NIZ | eps
VAL : START VAL END
| STR
| eps
以下是实现此语法的C代码的一部分:
void check() {
getSymbol();
if( sym == FIRST_LINE )
{
niz();
}
else {
printf("FIRST_LINE EXPECTED");
exit(1);
}
}
void niz() {
getSymbol();
if( sym == ERROR )
return;
if( sym == START ) {
back = 1;
val();
niz();
}
printf(" EPS OR START EXPECTED\n");
}
void val() {
getSymbol();
if( sym == ERROR )
return;
if( sym == START ) {
back = 0;
val();
getSymbol();
if( sym != END ) {
printf("END EXPECTED");
exit(1);
}
return;
}
if( sym == EMPTY_TAG || sym == STR)
return;
printf("START, STR, EMPTY_TAG OR EPS EXPECTED\n");
exit(1);
}
void getSymbol() {
int pom;
if(back == 1) {
back = 0;
return;
}
sym = getNextToken(cmd + offset, &pom);
offset += pom + 1;
}
编辑:以下是不满足此语法的XML文件示例:
<?xml version="1.0"?>
<VATCHANGES>
<DATE>15/08/2012</DATE>
<TIME>1452</TIME>
<EFDSERIAL>01KE000001</EFDSERIAL>
<CHANGENUM>1</CHANGENUM>
<VATRATE>A</VATRATE>
<FROMVALUE>16.00</FROMVALUE>
<TOVALUE>18.00</TOVALUE>
<VATRATE>B</VATRATE>
<FROMVALUE>2.00</FROMVALUE>
<TOVALUE>0.00</TOVALUE>
<VATRATE>C</VATRATE>
<FROMVALUE>5.00</FROMVALUE>
<TOVALUE>0.00</TOVALUE>
<DATE>25/05/2010</DATE>
<CHANGENUM>2</CHANGENUM>
<VATRATE>C</VATRATE>
<FROMVALUE>0.00</FROMVALUE>
<TOVALUE>4.00</TOVALUE>
</VATCHANGES>
它在输出端给出了END EXPECTED。
答案 0 :(得分:3)
首先,你的语法需要一些工作。假设前导码处理正确,则在NIZ的定义中存在基本错误。
NIZ : VAL NIZ | eps
VAL : START VAL END
| STR
| eps
所以我们输入NIZ,我们首先寻找VAL。问题是VAL的可能产品和 NIZ结束时的eps。因此,如果VAL不产生任何东西(即eps)并且在该过程中不消耗令牌(它不能正确,因为eps是生产),NIZ减少到:
NIZ: eps NIZ | eps
这不好。
从这些方面考虑更多的东西:我只是在没有真正的远见的情况下用它来超越纯粹的基本结构。
XML: START_LINE ELEMENT
ELEMENT: OPENTAG BODY CLOSETAG
OPENTAG: lt id(n) gt
CLOSETAG: lt fs id(n) gt
BODY: ELEMENT | VALUE
VALUE: str | eps
这是 super 基本。终端包括:
lt: '<'
gt: '>'
fs: '/'
str: any alphanumeric string excluding chars lt or gt.
id(n): any alphanumeric string excluding chars lt, gt, or fs.
我几乎可以感受到XML纯粹主义者现在对我的愤怒,但我想要了解的一点是,当语法定义明确时,RDP会逐字地写出来。显然,词法分析器(即令牌引擎)需要相应地处理终端。注意:id(n)是一个id-stack,用于确保正确关闭最内层标记,并且是解析器根据其管理标记ID的方式的属性。它不是传统的,但它使事情变得更容易。
这可以/应该清楚地扩展到包括独立元素声明和快捷元素闭包。例如,该语法允许使用此形式的元素:
<ElementName>...</ElementName>
但不是这种形式:
<ElementName/>
它也不会解释捷径终止,例如:
<ElementName>...</>
这种添加的计算显然会使语法复杂化,但也会使解析器更加健壮。就像我说的那样,上面的例子是带有大写字母B的 basic 。如果你真的要开始这个,那么你在设计语法时要考虑的是这些,因此你的RDP也是如此
无论如何,只要考虑一下你的语法中的一些修改可以/将如何使你更容易。