2010-11-12 108 views
2

底线:嵌入其他语言的Flex /野牛

如果您想使用Flex /野牛添加一个非常小的功能到C++,你会怎么做呢?例如,能够使用语法声明void xxx()函数:foo%%: xxx

原委:

一次,我已经编码的内置准备使用的CG/GLSL像素和顶点着色器从多个块的自定义着色器处理程序。我添加了一些功能,主要涉及静态编译(像“更好的预处理器”)。

例如,一些看起来像

#if LIGHT_TYPE == POINT 
    float lightStrength = dot(N, normalize(pos - lightPos)); 
#elif LIGHT_TYPE == DIRECTIONAL 
    float lightStrength = dot(N, lightDir); 
#endif 

纯宏,看起来像

[LightType = Point] 
[Require: pos, lightPos] 
float LightStrength() 
{ 
    !let %N Normal 
    return dot(%N, normalize(pos - lightPos)); 
} 
在我的 “语言”

。如您所见,可以为可变光源/材料类型提供“功能”。还可以“调用”其他函数,并标记特定着色器需要的统一/变化属性。

为什么这一切努力?因为(尤其是在像SM 2.0这样的早期版本中)属性存在很多限制,而且我的“编译器”生成了随时可用的着色器,其中包含必需的属性/变量列表,像素与顶点着色器之间的受管参数,优化了一些静态内容只是为了便于阅读,因为Cg编译器稍后会优化它)。

好的,但我没有写出所有这些赞美我自己或某事。

我在C#中编写了这个“编译器”,它最初是一个非常小的程序。但随着时间的推移,许多功能被添加,现在程序完全混乱,没有重构选项。另外,用C#编码意味着我不能直接在C++游戏中嵌入此编译器,迫使我生成进程以编译着色器(这需要很长时间)。

我想用C++和Flex/Bison工具包重写我的语言/编译器。我已经在Flex/Bison中编写了高效的数学解析器,所以我在这方面有点经验。但是有一件事我无法解决,而这是我的问题的一个主题。

我该如何将GLSL嵌入到我的语言中?在C#编译器中,我刚刚一行一行地检查一行是否以特殊字符开头(例如%或[),后来还使用string_replace和/或regex做了很多技巧&。

现在我想写下一个干净的Bison语法并正确地做。但包括GLSL的整个语法让我害怕。这是一个相当大而复杂的语言,不断发展。而且我会做的大部分事情都是传递所有这些GLSL代码。

如果您对GLSL/Cg /图形编程没有经验,这不是很重要。这个问题可以改写成“底线”。因此,如果您想使用Flex/Bison将一个非常小的特性添加到C++中,您将如何做到这一点?例如,能够使用语法声明void xxx()函数:foo%%: xxx

+2

Adob​​e劫持'flex'标志真的很糟糕。 (但是使用'yacc'和'lex'可能会更好。) – sbi 2010-11-12 19:29:06

+0

好点,改变它们 – programmer 2010-11-12 19:33:45

+1

有一个'gnu-flex'标签,BTW。 – 2010-11-13 06:22:19

回答

1

我在一个学校项目中添加了多线程机制,因此我必须处理这个问题。我所做的是我发现了一个BNF的pascal定义并复制了它,主要是让我的令牌等于99%的案例中的文本,并在我添加的新令牌的1%中添加了新的中间语言代码。帕斯卡很简单,所以BNF的定义是相对简单。 C++,并非如此。

Stroustroup的C++编程语言的语言语法实际上已经解析器准备好了,但这需要很多手工拷贝的代码。也许certain website可以帮助你找到为“标准”C++设置的bison/lex,然后你可以修改它。

编辑: 我发现我的yacc文件,所以这里是从我的PASCAL代码的一个小例子

procheader: PROCEDURE ID paramslist ';'{thread::inLocalDecl=true; $$="procedure "+$2+$3+";\n";} 
|   FUNCTION ID paramslist ':' ID ';'{thread::inLocalDecl=true; $$="function "+$2+$3+":"+$5+";\n";} 
| THREAD {thread::inThreadDecl=true; 
     thread::inArgDecl=true;} 
    ID {thread::curName=$3;} paramslist { thread::inArgDecl=false;} ';' 
{ 
    /*a lot of code to transform this custom construct into standard pascal*/ 
} 

前两个元素只是标准帕斯卡:我复制了输入令牌到输出字符串逐字(即我实际上没有修改输入文件中的任何内容)。

第三个元素(我的THREAD关键字)显然不是标准的pascal。所以我将输出转换成我可以用标准pascal编译的东西。

基本上编译我的“线程”pascal,我不得不采取我的源文件,通过我的解析器,然后编译输出。