- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
在进行OpenGL程序开发时,我需要自行解析`string`类型的Shader代码,抽取出里面的某些变量名和subroutine名.
由于找不到可用的GLSL Shader解析器,就照着虎书(《现代编译原理-c语言描述》)自己写了个LALR Generator,实际上包含了(词法分析器+语法分析器+格式化框架)的(LR(0)、SLR(1)、LALR(1)、LR(1))全自动生成,支持yacc的优先级指令和Shift/Reduce、Reduce/Reduc冲突解决功能.
本文的GLSL Shader的格式化工具(下载链接在这里https://files.cnblogs.com/files/bitzhuwei/GLSL.Formatter.net8.0.rar?t=1735122490&download=true ),就是用我的LALR Generator,根据GLSL4.60.8的文法生成的,如下所述.
#extractor <GLSL4.60.8.st.ext>
translation_unit :
external_declaration
| translation_unit external_declaration
;
external_declaration :
function_definition
| declaration
| ';'
;
function_definition :
function_prototype compound_statement/* compound_statement_no_new_scope */
;
variable_identifier :
'identifier'
;
primary_expression :
variable_identifier
| 'intConstant'
| 'uintConstant'
| 'floatConstant'
| 'boolConstant'
| 'doubleConstant'
| '(' expression ')'
;
postfix_expression :
primary_expression
| postfix_expression '[' integer_expression ']'
| function_call
| postfix_expression '.' 'identifier' // FIELD_SELECTION
| postfix_expression '++'
| postfix_expression '--'
;
integer_expression :
expression
;
function_call :
function_call_or_method
;
function_call_or_method :
function_call_generic
;
function_call_generic :
function_call_header_with_parameters ')'
| function_call_header_no_parameters ')'
;
function_call_header_no_parameters :
function_call_header 'void'
| function_call_header
;
function_call_header_with_parameters :
function_call_header assignment_expression
| function_call_header_with_parameters ',' assignment_expression
;
function_call_header :
function_identifier '('
;
function_identifier :
type_specifier
| postfix_expression
;
unary_expression :
postfix_expression
| '++' unary_expression
| '--' unary_expression
| unary_operator unary_expression
;
unary_operator :
'+'
| '-'
| '!'
| '~'
;
multiplicative_expression :
unary_expression
| multiplicative_expression '*' unary_expression
| multiplicative_expression '/' unary_expression
| multiplicative_expression '%' unary_expression
;
additive_expression :
multiplicative_expression
| additive_expression '+' multiplicative_expression
| additive_expression '-' multiplicative_expression
;
shift_expression :
additive_expression
| shift_expression '<<' additive_expression
| shift_expression '>>' additive_expression
;
relational_expression :
shift_expression
| relational_expression '<' shift_expression
| relational_expression '>' shift_expression
| relational_expression '<=' shift_expression
| relational_expression '>=' shift_expression
;
equality_expression :
relational_expression
| equality_expression '==' relational_expression
| equality_expression '!=' relational_expression
;
and_expression :
equality_expression
| and_expression '&' equality_expression
;
exclusive_or_expression :
and_expression
| exclusive_or_expression '^' and_expression
;
inclusive_or_expression :
exclusive_or_expression
| inclusive_or_expression '|' exclusive_or_expression
;
logical_and_expression :
inclusive_or_expression
| logical_and_expression '&&' inclusive_or_expression
;
logical_xor_expression :
logical_and_expression
| logical_xor_expression '^^' logical_and_expression
;
logical_or_expression :
logical_xor_expression
| logical_or_expression '||' logical_xor_expression
;
conditional_expression :
logical_or_expression
| logical_or_expression '?' expression ':' assignment_expression
;
assignment_expression :
conditional_expression
| unary_expression assignment_operator assignment_expression
;
assignment_operator :
'='
| '*='
| '/='
| '%='
| '+='
| '-='
| '<<='
| '>>='
| '&='
| '^='
| '|='
;
expression :
assignment_expression
| expression ',' assignment_expression
;
constant_expression :
conditional_expression
;
declaration :
function_prototype ';'
| init_declarator_list ';'
| 'precision' precision_qualifier type_specifier ';'
| type_qualifier 'identifier' '{' struct_declaration_list '}' ';'
| type_qualifier 'identifier' '{' struct_declaration_list '}' 'identifier' ';'
| type_qualifier 'identifier' '{' struct_declaration_list '}' 'identifier' array_specifier ';'
| type_qualifier ';'
| type_qualifier 'identifier' ';'
| type_qualifier 'identifier' identifier_list ';'
;
identifier_list :
',' 'identifier'
| identifier_list ',' 'identifier'
;
function_prototype :
function_declarator ')'
;
function_declarator :
function_header
| function_header_with_parameters
;
function_header_with_parameters :
function_header parameter_declaration
| function_header_with_parameters ',' parameter_declaration
;
function_header :
fully_specified_type 'identifier' '('
;
parameter_declarator :
type_specifier 'identifier'
| type_specifier 'identifier' array_specifier
;
parameter_declaration :
type_qualifier parameter_declarator
| parameter_declarator
| type_qualifier parameter_type_specifier
| parameter_type_specifier
;
parameter_type_specifier :
type_specifier
;
init_declarator_list :
single_declaration
| init_declarator_list ',' 'identifier'
| init_declarator_list ',' 'identifier' array_specifier
| init_declarator_list ',' 'identifier' array_specifier '=' initializer
| init_declarator_list ',' 'identifier' '=' initializer
;
single_declaration :
fully_specified_type
| fully_specified_type 'identifier'
| fully_specified_type 'identifier' array_specifier
| fully_specified_type 'identifier' array_specifier '=' initializer
| fully_specified_type 'identifier' '=' initializer
;
fully_specified_type :
type_specifier
| type_qualifier type_specifier
;
invariant_qualifier :
'invariant'
;
interpolation_qualifier :
'smooth'
| 'flat'
| 'noperspective'
;
layout_qualifier :
'layout' '(' layout_qualifier_id_list ')'
;
layout_qualifier_id_list :
layout_qualifier_id
| layout_qualifier_id_list ',' layout_qualifier_id
;
layout_qualifier_id :
'identifier'
| 'identifier' '=' constant_expression
| 'shared'
;
precise_qualifier :
'precise'
;
type_qualifier :
single_type_qualifier
| type_qualifier single_type_qualifier
;
single_type_qualifier :
storage_qualifier
| layout_qualifier
| precision_qualifier
| interpolation_qualifier
| invariant_qualifier
| precise_qualifier
;
storage_qualifier :
'const'
| 'in'
| 'out'
| 'inout'
| 'centroid'
| 'patch'
| 'sample'
| 'uniform'
| 'buffer'
| 'shared'
| 'coherent'
| 'volatile'
| 'restrict'
| 'readonly'
| 'writeonly'
| 'subroutine'
| 'subroutine' '(' type_name_list ')'
;
type_name_list :
'type_name'
| type_name_list ',' 'type_name'
;
type_specifier :
type_specifier_nonarray
| type_specifier_nonarray array_specifier
;
array_specifier :
'[' ']'
| '[' conditional_expression ']'
| array_specifier '[' ']'
| array_specifier '[' conditional_expression ']'
;
type_specifier_nonarray :
'void'
| 'float'
| 'double'
| 'int'
| 'uint'
| 'bool'
| 'vec2'
| 'vec3'
| 'vec4'
| 'dvec2'
| 'dvec3'
| 'dvec4'
| 'bvec2'
| 'bvec3'
| 'bvec4'
| 'ivec2'
| 'ivec3'
| 'ivec4'
| 'uvec2'
| 'uvec3'
| 'uvec4'
| 'mat2'
| 'mat3'
| 'mat4'
| 'mat2x2'
| 'mat2x3'
| 'mat2x4'
| 'mat3x2'
| 'mat3x3'
| 'mat3x4'
| 'mat4x2'
| 'mat4x3'
| 'mat4x4'
| 'dmat2'
| 'dmat3'
| 'dmat4'
| 'dmat2x2'
| 'dmat2x3'
| 'dmat2x4'
| 'dmat3x2'
| 'dmat3x3'
| 'dmat3x4'
| 'dmat4x2'
| 'dmat4x3'
| 'dmat4x4'
| 'atomic_uint'
| 'sampler2D'
| 'sampler3D'
| 'samplerCube'
| 'sampler2DShadow'
| 'samplerCubeShadow'
| 'sampler2DArray'
| 'sampler2DArrayShadow'
| 'samplerCubeArray'
| 'samplerCubeArrayShadow'
| 'isampler2D'
| 'isampler3D'
| 'isamplerCube'
| 'isampler2DArray'
| 'isamplerCubeArray'
| 'usampler2D'
| 'usampler3D'
| 'usamplerCube'
| 'usampler2DArray'
| 'usamplerCubeArray'
| 'sampler1D'
| 'sampler1DShadow'
| 'sampler1DArray'
| 'sampler1DArrayShadow'
| 'isampler1D'
| 'isampler1DArray'
| 'usampler1D'
| 'usampler1DArray'
| 'sampler2DRect'
| 'sampler2DRectShadow'
| 'isampler2DRect'
| 'usampler2DRect'
| 'samplerBuffer'
| 'isamplerBuffer'
| 'usamplerBuffer'
| 'sampler2DMS'
| 'isampler2DMS'
| 'usampler2DMS'
| 'sampler2DMSArray'
| 'isampler2DMSArray'
| 'usampler2DMSArray'
| 'image2D'
| 'iimage2D'
| 'uimage2D'
| 'image3D'
| 'iimage3D'
| 'uimage3D'
| 'imageCube'
| 'iimageCube'
| 'uimageCube'
| 'imageBuffer'
| 'iimageBuffer'
| 'uimageBuffer'
| 'image1D'
| 'iimage1D'
| 'uimage1D'
| 'image1DArray'
| 'iimage1DArray'
| 'uimage1DArray'
| 'image2DRect'
| 'iimage2DRect'
| 'uimage2DRect'
| 'image2DArray'
| 'iimage2DArray'
| 'uimage2DArray'
| 'imageCubeArray'
| 'iimageCubeArray'
| 'uimageCubeArray'
| 'image2DMS'
| 'iimage2DMS'
| 'uimage2DMS'
| 'image2DMSArray'
| 'iimage2DMSArray'
| 'uimage2DMSArray'
| struct_specifier
| 'type_name'
;
precision_qualifier :
'highp'
| 'mediump'
| 'lowp'
;
struct_specifier :
'struct' 'type_name'/* 'identifier' */ '{' struct_declaration_list '}'
| 'struct' '{' struct_declaration_list '}'
;
struct_declaration_list :
struct_declaration
| struct_declaration_list struct_declaration
;
struct_declaration :
type_specifier struct_declarator_list ';'
| type_qualifier type_specifier struct_declarator_list ';'
;
struct_declarator_list :
struct_declarator
| struct_declarator_list ',' struct_declarator
;
struct_declarator :
'identifier'
| 'identifier' array_specifier
;
initializer :
assignment_expression
| '{' initializer_list '}'
| '{' initializer_list ',' '}'
;
initializer_list :
initializer
| initializer_list ',' initializer
;
declaration_statement :
declaration
;
statement :
compound_statement
| simple_statement
;
simple_statement :
declaration_statement
| expression_statement
| selection_statement
| switch_statement
| case_label
| iteration_statement
| jump_statement
;
compound_statement :
'{' '}'
| '{' statement_list '}'
;
/* merge into statement
statement_no_new_scope :
compound_statement_no_new_scope
| simple_statement
;
*/
/* merge into compound_statement
compound_statement_no_new_scope :
'{' '}'
| '{' statement_list '}'
;
*/
statement_list :
statement
| statement_list statement
;
expression_statement :
';'
| expression ';'
;
selection_statement :
'if' '(' expression ')' selection_rest_statement
;
selection_rest_statement :
statement 'else' statement
| statement
;
condition :
expression
| fully_specified_type 'identifier' '=' initializer
;
switch_statement :
'switch' '(' expression ')' '{' switch_statement_list '}'
;
switch_statement_list :
empty
| statement_list
;
case_label :
'case' expression ':'
| 'default' ':'
;
iteration_statement :
'while' '(' condition ')' statement/* statement_no_new_scope */
| 'do' statement 'while' '(' expression ')' ';'
| 'for' '(' for_init_statement for_rest_statement ')' statement/* statement_no_new_scope */
;
for_init_statement :
expression_statement
| declaration_statement
;
conditionopt :
condition
| empty
;
for_rest_statement :
conditionopt ';'
| conditionopt ';' expression
;
jump_statement :
'continue' ';'
| 'break' ';'
| 'return' ';'
| 'return' expression ';'
| 'discard' ';'
;
// lexical statements
// no need : 'struct' 'identifier' '{' struct_declaration_list '}'
// now I changed it into 'struct' 'type_name' '{' struct_declaration_list '}'
// only identifier next to 'struct' is a user-defined type and should be a 'type_name' token.
'type_name' %%<'struct'>[a-zA-Z_][a-zA-Z0-9_]*%%
'intConstant' %%[-+]?[0-9]+%%
'intConstant' %%0x[0-9A-Fa-f]+%%
'uintConstant' %%[-+]?[0-9]+[uU]%%
'uintConstant' %%0x[0-9A-Fa-f]+[uU]%%
'floatConstant' %%[-+]?[0-9]+([.][0-9]+)?([Ee][-+]?[0-9]+)?[fF]%%
'boolConstant' %%true/[^a-zA-Z0-9_]%%
'boolConstant' %%false/[^a-zA-Z0-9_]%%
'doubleConstant' %%[-+]?[0-9]+([.][0-9]+)?([Ee][-+]?[0-9]+)?%%
'identifier' %%[a-zA-Z_][a-zA-Z0-9_]*%%
%grammarName GLSL
%blockComment on
%inlineComment on
有了解析器,就有了单词流List<Token>和语法树Node。面对GLSL代码的语法树,我们如何对源代码进行格式化呢?
格式化的目的是让源代码从书写上更适宜人类阅读。具体来说,格式化要做的事,只是增减某些空白符(空格、tab符、换行符)而已,不会修改具有语法意义的内容.
在C#中, 。
if (x >0) {t = x;x = 0;
}
会被格式化为 。
if (x > 0) {
t = x; x = 0;
}
而 。
if (x > 0) {t = x;
x= 0;
}
会被格式化为 。
if (x > 0) {
t = x;
x = 0;
}
同样意义的源代码,格式化结果却不同。这有些复杂.
我们将问题拆开,一步一步来.
首先,我们忽略多行注释blockComment、单行注释inlineComment和源代码中原有的空白符.
此时,一个if(x>0){t=x;x=0;}就应当被格式化为:
if (x > 0) {
t = x;
x = 0;
}
也就是说,语法树中的每一部分,都可以自己判断出应当如何格式化。用递归的方式遍历语法树即可.
现在来考虑注释。注释可能出现在List<Token>(词法分析器的分析结果)里的任意位置上,属实调皮。于是就有这样一个想法,利用C#的yield return语法糖,我们执行下述算法:
遍历`List<Token>`:
如果下一个要进行格式化的Token是注释,那么就在当前位置输出它并换行。
如果下一个要进行格式化的Token不是注释,那么就用`yield return`的方式,在语法树上格式化地输出它(输出它+某些空白符)。
只要在语法树每输出一个Token时,都进行一次yield return(return什么无所谓),那么yield return就能和遍历List<Token>的过程同步完成.
现在能够带着注释格式化了,但是无法解决这样的情况:上一行和下一行代码之间有好几个空行(即换行符),上述格式化过程会无视之.
完全的格式化算法要继承上述方法的思路,并加强如下:
语法树的各类语法块`Node`分别实现自己内部的格式化办法。
语法块`Node`要根据上一级`Node`传递来的要求,在输出自己内部的第一个`Token`之前,先输出多少个换行符和空格。
语法块`Node`要告知自己的每个下一级`Node`,它希望这些子级先输出多少个换行符和空格。
每个`Token`根据(上级传递来的要求+它与前一个`Token`之间的位置关系(间隔多少空格和换行符))输出自己前面的空白符,而后输出自己的内容。
每个语法块`Node`都服从直接上级的要求,并对各个直接下级发出要求。通过这样接力的方式,就可以通过遍历一次语法树来输出格式化的代码了.
同学们可以下载链接中的工具查看效果,里面还有一些示例shader.
。
最后此篇关于一个GLSLShader的格式化算法(LALR解析器)的文章就讲到这里了,如果你想了解更多关于一个GLSLShader的格式化算法(LALR解析器)的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
让我们说相同的语法不是 LR(1),我们可以有把握地说这个语法也不是 LALR 吗? 如果不是,语法成为 LALR 的条件是什么? (或者使语法不是 LALR 的条件是什么) 谢谢您的帮助! 最佳答案
关于LALR(1)解析器冲突的一些问题,主要涉及解析的细节: 根据教科书中描述的不同 LALR(1) 解析器,如果遇到 shift/reduce 冲突,那么这表明语法不是 LALR(1) 开始,对吗?
LALR(2) 是否能够自然地处理悬空的 else 情况(没有任何特殊规则,就像 LALR(1) 一样)? 谢谢 最佳答案 不,悬空的 else 问题是模棱两可的,因此再多的前瞻也无济于事。 关于pa
我正在使用一些解析器和词法分析器生成工具(类似于 Lex 和 Bison,但用于 C#)来生成将字符串解析为抽象语法树的程序,这些语法树可以在以后进行评估。 我想进行错误恢复(即在生成的抽象句子树中报
我最近对 LALR 的研究足以写一篇 LALR generator ,并且我正在尝试为其构造一个 java 或 c# 风格的语法(其开头指定为 here )。 我知道编写解析器生成器需要额外的努力
我已经被这个问题困扰了一段时间了。我想解析一些简单的东西: 喜欢:word1 word2 .. wordN 讨厌:word1 word2 .. wordN 我正在使用柠檬+Flex。目前我的语法看起来
我有一个简单的 LALR(1) 语法,但是我遇到了一个问题。 start ::= spec. spec ::= MOD STRING top_stmt. spec ::= top_stmt. top_
我正在尝试为一种由赋值组成的非常简单的语言生成 LALR 语法。例如: foo = "bar" bar = 42 该语言还应该处理值列表,例如: foo = 1, 2, 3 但我也想处理多行列表: f
许多网站都说 Packrat 解析器可以在线性时间内解析输入。 因此,乍一看,它们比由 yacc 或 bison 工具构建的 LALR 解析器更快。 我想知道在使用通用输入(如编程语言源文件)而不是任
我一直在使用 lex/yacc,现在我正在尝试切换到 ANTLR。主要问题是 ANTLR 是一个 LL(*) 解析器,而 yacc 是 LALR。我习惯于自下而上地思考,我并不完全知道 LL 语法的优
这个问题在这里已经有了答案: What is the difference between LR, SLR, and LALR parsers? (8 个回答) 2年前关闭。 我知道 LR 和 LAL
我现在正在我的编译理论类(class)中学习解析器。我需要找到一个在 LL(1) 中但不在 LALR 中的语法示例。我知道它应该存在。请帮我想出这个问题的最简单的例子。 最佳答案 Some googl
我们正在尝试(巧妙地)生成一个解析器和词法分析器,从字符串而不是标准输入中读取字符。 我们开始修改代码中包含的计算器示例: http://code.google.com/p/lalr-scm/sour
我一直在使用 PLY 为我的语言构建一个解析器,但是我遇到了移位/归约冲突,这给我带来了一些麻烦。我的语言具有通用类型,其语法与 C++ 模板相同。所以现在我有这样的规则: expressio
我正在尝试使用 ply 构建一个脚本工具。但是我被一些解析错误阻止了。通过将这些 p_xxx 函数移动到不同的位置,我得到了不同的语法错误。有人可以提供帮助吗? 例如如果我将 p_funcall 移到
我正在使用 PLY python 包为 C 的子集构建前端编译器,但我仍然在努力理解自下而上的解析器(特别是 LALR)是如何工作的。我用给定的语法编写了一个简单的程序来看看它是如何工作的: expr
我正在尝试解析一种上下文无关的语言,称为 Context Free Art .我使用类似 YACC 的 JS LALR(1) 解析器生成器在 Javascript 中创建了它的解析器 JSCC . 以
大家好,我是 cup 解析器的新手,我的问题是,在我的语法中的 trans 定义中,我有空 trans,我的问题是,这是正确的吗? 例如,在我的语法中,我有 INIT -> A B -c- A -
我想从输入中获取参数。例如:输入:12+10。在运行我的计算器之后。 我想得到 12 和 10。我知道,我必须在 Parse(pParser, hTokenID, sTokenData, pArg);
有人可以描述从 LALR(1) 的给定语法生成所需表(action、goto)的算法吗? 我已经读过 http://en.wikipedia.org/wiki/LALR_parser http://e
我是一名优秀的程序员,十分优秀!