如何为WDI写一个野牛语法?

时间:2010-05-27 14:11:37

标签: html c parsing grammar bison

我需要一些关于野牛语法构建的帮助。

从我的另一个问题: 我正在尝试编写一种用于编写标记代码的元语言(例如xml和html),它可以直接嵌入到C / C ++代码中。 这是一个用这种语言编写的简单示例,我称之为WDI(Web开发接口):

 /*
  * Simple wdi/html sample source code
  */
 #include <mySite>

 string name = "myName";
 string toCapital(string str);

 html
 {
  head {
   title { mySiteTitle; }
   link(rel="stylesheet", href="style.css");
  }
  body(id="default") {
   // Page content wrapper
   div(id="wrapper", class="some_class") {
    h1 { "Hello, " + toCapital(name) + "!"; }

    // Lists post
    ul(id="post_list") {
     for(post in posts) {
      li { a(href=post.getID()) { post.tilte; } }
     }
    }
   }
  }
 }

基本上它是一个C源代码,具有用户友好的html界面。 正如您所看到的那样,传统的基于标签的样式被类似C的样式替换,其中的块由花括号分隔。 我需要构建一个解释器来将此代码转换为html,然后将其插入到C中,以便可以编译它。 C部分保持不变。 在wdi源代码内部没有必要使用print,每个return语句都将用于输出(在printf函数中)。 该程序的输出将是干净的HTML代码。

因此,例如标题1标签将被转换为:

h1 { "Hello, " + toCapital(name) + "!"; }
// would become:
printf("<h1>Hello, %s!</h1>", toCapital(name));

我的主要目标是创建一个解释器,将wdi源转换为html,如下所示:

tag(attributes) {content} =&gt; <tag attributes>content</tag>

其次,解释器返回的html代码必须用printfs插入到C代码中。 wdi中发生的变量和函数也应该进行排序,以便将它们用作printf参数(样本源中的toCapital(name)的情况)。

以下是我的flex / bison文件:

id        [a-zA-Z_]([a-zA-Z0-9_])*
number    [0-9]+
string    \".*\"

%%

{id} {
        yylval.string = strdup(yytext);
        return(ID);
    }

{number} {
        yylval.number = atoi(yytext);
        return(NUMBER);
    }

{string} {
        yylval.string = strdup(yytext);
        return(STRING);
    }

"(" { return(LPAREN); }
")" { return(RPAREN); }
"{" { return(LBRACE); }
"}" { return(RBRACE); }
"=" { return(ASSIGN); }
"," { return(COMMA);  }
";" { return(SEMICOLON); }

\n|\r|\f { /* ignore EOL */ }
[ \t]+   { /* ignore whitespace */ }
.        { /* return(CCODE); Find C source */ }

%%

%start wdi
%token LPAREN RPAREN LBRACE RBRACE ASSIGN COMMA SEMICOLON CCODE QUOTE

%union
{
    int number;
    char *string;
}

%token <string> ID STRING
%token <number> NUMBER

%%
wdi
    : /* empty */
    | blocks
    ;

blocks
    : block
    | blocks block
    ;

block
    : head SEMICOLON
    | head body
    ;

head
    : ID
    | ID
    attributes
    ;

attributes
    : LPAREN RPAREN
    | LPAREN attribute_list RPAREN
    ;

attribute_list
    : attribute
    | attribute COMMA attribute_list
    ;

attribute
    : key ASSIGN value
    ;

key
    : ID {$$=$1}
    ;

value
    : STRING {$$=$1}
    /*| NUMBER*/
    /*| CCODE*/
    ;

body
    : LBRACE content RBRACE
    ;

content
    : /* */
    | blocks
    | STRING SEMICOLON
    | NUMBER SEMICOLON
    | CCODE
    ;

%%

我在为语言定义正确的语法时遇到了困难,特别是在拆分WDI和C代码时。我刚开始学习语言处理技术,所以我需要一些方向。 有人可以更正我的代码或提供一些解决此问题的正确方法的例子吗?

1 个答案:

答案 0 :(得分:2)

如果您的目的是解析 C代码和嵌入式WDI代码,那么您将陷入困境。 LALR(1)解析器生成器(包括Bison)在解析C时非常糟糕,更不用说比C更复杂的东西(意思是C + WDI)。

要么你必须:

a)学习如何通过纠结解析和符号表构造来使Bison解析C(意思是,与GNU GCC斗争以了解他们是如何做到的),

b)切换到更强大的解析器生成器,例如GLR解析器生成器(Bison有一个选项),并学习如何处理模糊语法以及如何解决它们,

c)将WDI设计为一种岛语法,其目标是选择WDI代码并将不是WDI的所有内容保留为不透明字符串(在您的情况下,注定要输出为假定的C​​代码)。后一种方法更容易,并且大致是所有网页语言(ASP,PHP,JSP ...)的功能。好处是,这更容易,你只需要为WDI本身写一个语法,并且一个词法分析器将把所有不是WDI的东西作为一个abitrary字符串。缺点是你不能使WDI和C很好地交互/和/或用你的解析器检查WDI程序的有效性。 有关更多背景,请参阅此SO问题:

Island grammar antlr3

如果您在开始此项目之前更详细地了解编译器技术,这会更容易。