2

底线:

如果你想使用 Flex/Bison 在 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 和/或正则表达式做了许多技巧和黑客攻击。

现在我想写下一个干净的 Bison 语法并正确地做。但是包括 GLSL 的整个语法让我害怕。它是一种庞大而复杂的语言,不断发展。无论如何,我最想做的就是传递所有这些 GLSL 代码。

如果您根本没有 GLSL/Cg/图形编程经验,这不是很重要。这个问题可以改写成“底线”。

那么,如果你想使用 Flex/Bison 在 C++ 中添加一个非常小的特性,你会怎么做呢?例如,void xxx()使用语法声明函数的能力:foo%%: xxx

4

1 回答 1

1

我曾经为一个学校项目的 pascal 添加了多线程机制,所以我不得不处理这个问题。我所做的是我找到了一个 Pascal 的 BNF 定义并复制了它,主要是让我的标记在 99% 的情况下等于文本,并在我添加的 1% 的新标记中添加新的中间语言代码。Pascal很简单,所以BNF的定义也比较简单。C++,没那么多。

Stroustroup 的 C++ 编程语言具有几乎可用于解析器的语言语法,但需要手动复制大量代码。也许某个网站可以帮助您找到“标准”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 关键字)显然不是标准的帕斯卡。所以我把输出转换成我可以用标准帕斯卡编译的东西。

基本上要编译我的“线程”帕斯卡,我必须获取我的源文件,通过我的解析器,然后编译输出。

于 2010-11-12T23:02:37.043 回答