ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Slang 关键词与内置语法全解析:语法声明模型、核心模块词汇与保留前缀

2026/9/19 6:12:32 拓冰建站 浏览量
Slang 关键词与内置语法全解析:语法声明模型、核心模块词汇与保留前缀 Slang 关键词与内置语法全解析语法声明模型、核心模块词汇与保留前缀【免费下载链接】slangMaking it easier to work with shaders项目地址: https://gitcode.com/GitHub_Trending/sl/slang本篇技术指南系统梳理 Slang 编译器中关键词的真实来源与注册机制绝大多数看似关键词的标识符并非词法层保留字而是绑定到解析回调的SyntaxDecl语法声明。读者读完将理解struct、func、if、__target_intrinsic等词汇分别由词法器、解析器语法表还是核心模块*.meta.slang提供掌握新增或重命名一个关键词时需要修改的具体文件与注册入口并能够区分编译器内部词汇__前缀与可被用户遮蔽的上下文关键字。关键词从何而来语法即声明的模型理解 Slang 关键词体系的第一步是接受一个非显然的事实大多数关键词不是词法层的保留字。它们以TokenType::Identifier的形式到达解析器完整 Token 分类见 tokens.md只有在活动环境中存在某个SyntaxDecl把它们绑定到解析回调时它们才成为关键词。因此新增或重命名一个关键词修改的是解析器的语法表或核心模块源码而不是词法器。关键词共有三个来源硬编码的语句关键词位于 slang-parser.cpp。语句解析器通过LookAheadToken(if)、LookAheadToken(for)等直接比对标识符并分派到专用的解析函数。解析器的SyntaxParseInfo语法表即 slang-parser.cpp 中的数组g_parseSyntaxEntries[]定义于 slang-parser.cpp。getSyntaxParseInfos()将该数组以视图形式暴露slang-parser.cpppopulateBaseLanguageModule()则把它注册进默认环境slang-parser.cpp。这是声明关键字、修饰符关键字和表达式关键字的来源。核心模块*.meta.slang声明。这些元模块core.meta.slang、hlsl.meta.slang、glsl.meta.slang、diff.meta.slang声明内置类型、函数与运算符为默认环境贡献名字。它们在编译器启动时被处理但属于内置词汇而非关键词只有SyntaxDecl绑定会驱动解析回调而一个已知类型名只参与少数受限的类型消歧决策。三条来源的注册路径由addBuiltinSyntaxImpl统一落地slang-parser.cpp它为每个词条创建一个SyntaxDecl记录其syntaxClass与parseCallback打上PublicModifier后加入当前作用域addBuiltinSyntax与addSimpleModifierSyntax后者固定使用parseSimpleSyntax回调是其两个常用模板封装。词法层识别的关键字词法器不识别任何字母形式的关键字。在词法器/Token 目录中被显式拼写的唯一内容是标点与运算符——完整清单见 tokens.md 与 slang-token-defs.h。该头文件通过PUNCTUATION(...)宏声明了Semicolon;、Scope::、RightArrow-、DoubleRightArrow以及全部Op*运算符TokenKind拼写TokenKind拼写Semicolon;OpAssignOpAddOpSub-OpMul*OpDiv/OpMod%OpNot!OpBitNot~OpLshOpRshOpEqlOpNeq!OpGreaterOpLessOpGeqOpLeqOpAndOpOr||OpBitAndOpBitOr|OpBitXor^OpIncOpDec--OpAddAssign...赋值类复合运算符等见头文件运算符的完整词法表属于 grammar.md 的范畴本文不重复列出。解析器注册的语法关键字Slang 关键词的主体由解析器而非词法器识别。语句关键字由语句解析器直接匹配声明、修饰符与表达式关键字则注册在解析器的语法声明表g_parseSyntaxEntries[]中从而可以通过syntax/attribute_syntax声明被重定义或扩展。这两种声明写作syntax name [: SyntaxClass] [ existingKeyword];attribute_syntax [Name(param : Type, ...)] : SyntaxClass;两者都要命名一个 AST 节点类由parseSyntaxDecl与parseAttributeSyntaxDecl通过ASTBuilder::findSyntaxClass解析因此任何一种形式都无法引入编译器尚未声明的节点——扩展点是已有节点的新拼写而非新节点。这正是两种形式在实践中只出现在核心模块的原因例如 core.meta.slang 中的syntax constexpr : ConstExprModifier;与attribute_syntax [ExperimentalModule] : ExperimentalModuleAttribute;即为代表。 existingKeyword别名形式会复制被命名关键词的解析回调和语法类使新拼写成为即插即用的别名在source_commit时刻树中没有任何.slang源码使用该别名形式。语句关键字语句关键字由语句解析器通过直接比对标识符识别。以下行号均指 slang-parser.cpp 在source_commit时刻的版本关键字解析位置if第 6935 行LookAheadToken(if)位于Parser::ParseStatement第 6928 行其第二个参数是AllowCaseDefaultStatements标志对应case行所述。第二个前视在第 6937 行向前看两个 token 是否为let从而把if let绑定形式路由到parseIfLetStatement第 7308 行而非parseIfStatement第 7397 行else在后者内部第 7406 行被消费for第 6946 行语句入口。编译期形式从parseCompileTimeStmt第 6914 行进入它先读取$然后在第 6917 行检查for才调用parseCompileTimeForStmt第 6868 行当前仓库中实测位于第 6958 行。其头不是普通的(init; cond; update)三元组而是$for(i in Range(N))parseCompileTimeForStmt读取循环变量然后读取字面 tokenin与Range再读取一个或两个范围表达式——Range(end)或Range(begin, end)while第 6948 行do第 6950 行break第 6952 行continue第 6954 行return第 6956 行switch第 6965 行__target_switch第 6967 行parseTargetSwitchStmt编译器内部__stage_switch第 6969 行parseStageSwitchStmt编译器内部__intrinsic_asm第 6971 行parseIntrinsicAsmStmt编译器内部case第 6973 行以及 switch 体内的第 6633、6663 行。自allowCaseDefault参数加入后语句解析器在任何位置都接受case再给出诊断ParseCaseStmt总是构建节点未传入AllowCaseDefaultStatements::Allow的调用方会报告CaseOutsideSwitchE39999第 6977 行default第 6980 行以及 switch 体内的第 6639、6663 行。与case形态相同无条件解析除非调用方允许否则在第 6985 行报告DefaultOutsideSwitchE39999__GPU_FOREACH第 6987 行ParseGpuForeachStmt编译器内部discard第 6958 行defer第 6993 行throw第 7001 行__requireCapability第 7005 行Parser::ParseRequireCapabilityStatement第 7626 行编译器内部catchParser::ParseDoCatchStatement第 7506 行由ParseDoStatement在第 7551 行进入。catch不与语句层的try配对这些关键字不在语法声明表中因为 Slang 将控制流视为封闭文法用户代码无法重定义它们。注意try是表达式关键字见下文表达式关键字语句层的异常处理器是do { ... } catch ( ... ) { ... }解析于 slang-parser.cpp 第 7482-7513 行。错误参数可选——裸catch捕获所有错误类型——并且ParseDoCatchStatement会在后面继续出现catch时循环把每个CatchStmt作为下一个的tryBody使catch子句链嵌套而非形成扁平列表。每个编译器内部行解析固定形式读者在核心模块源码中遇到它们时可以据此识别__stage_switch { case stage: ... default: ... }与__target_switch共享parseTargetSwitchStmtImplcase后的标签是能力名由findCapabilityName解析无法识别时直接诊断而非当作标识符。__intrinsic_asm text;可选地在分号前跟一个逗号分隔的参数列表如__intrinsic_asm (gl_SubGroupID);。__GPU_FOREACH(device, gridDims, LAMBDA(uint3 id) { ... });——字面 tokenLAMBDA是文法的一部分不是用户提供的名字。__requireCapability(capability, ...);逗号分隔的能力名列表每个同样由findCapabilityName解析。声明关键字声明关键字通过_makeParseDecl(...)定义于 slang-parser.cpp 第 10696 行注册进g_parseSyntaxEntries[]数组起点位于 slang-parser.cpp。以双下划线__开头的标识符有意被命名空间化作为编译器内部/非稳定词汇关键字解析内容typedefC 风格类型别名parseTypeDeftypealiasSlang 风格类型别名parseTypeAliasDeclassociatedtype接口关联类型parseAssocType第 4307 行__constraint接口级约束需求parseInterfaceConstraintDecl第 4349 行__associatedfunc接口关联函数parseAssocFunctype_param模块级泛型类型参数parseGlobalGenericTypeParamDecl__generic泛型参数列表头parseGenericDecl__generic_value_param模块级泛型值参数parseGlobalGenericValueParamDeclextension,__extension类型扩展parseExtensionDecl__func_extension自定义导数的函数扩展简写parseFuncExtensionDecl实验特性由-experimental-feature门控interface接口parseInterfaceDecl__init构造函数parseConstructorDecl__subscript下标parseSubscriptDeclproperty属性parsePropertyDeclsemanticHLSL 风格语义声明parseSemanticDeclcbufferHLSL 常量缓冲声明parseHLSLCBufferDecltbufferHLSL 纹理缓冲声明parseHLSLTBufferDeclsyntax用户自定义语法parseSyntaxDeclattribute_syntax属性语法parseAttributeSyntaxDeclimport,__import模块导入parseImportDecl__include包含指令parseIncludeDeclmodule模块声明parseModuleDeclarationDeclimplementing模块实现声明parseImplementingDecllet不可变绑定parseLetDeclvar可变绑定parseVarDeclfunc函数声明parseFuncDeclnamespace命名空间块parseNamespaceDeclusingusing 指令parseUsingDecl__ignored_block编译器内部忽略块__transparent_block编译器内部透明块__file_decl编译器内部按文件声明的分组__require_capability能力需求parseRequireCapabilityDecl其中三行__形式值得单独展开因为仅凭回调名无法推断其形态__constraint type type;陈述类型相等需求__constraint type : type;陈述子类型需求。两者都会成为所在接口的GenericTypeConstraintDecl成员精化从基接口继承的This或关联类型——interface IDerived : IBase { __constraint DataType This; }要求每个符合者对This.DataType This成立。它只在接口体内有意义。__associatedfunc function-type name;——一个类型表达式后跟需求名。核心模块用它声明自动微分函数需求例如 core.meta.slang 中的static __associatedfunc FwdDiffFuncTypeFType fwd_diff;。__func_extension接受一个高阶目标表达式、一个参数列表、可选throws子句、可选- result type以及一个函数体。目标由语法声明查找而非硬编码的运算符列表解析因此写作某个微分表达式关键字之一如 hlsl.meta.slang 中的__func_extensionT : __BuiltinFloatingPointType, let N : int fwd_diff(CoopVecT, N::__subscript::get)(DifferentialPairCoopVecT, N self, int index) - DifferentialPairT { ... }。struct、class和enum也是声明关键字但不通过g_parseSyntaxEntries[]/_makeParseDecl注册。解析器改为在类型说明符解析器中直接做标识符前视分派slang-parser.cpp 第 3425-3445 行该路径由ParseDeclWithModifiersslang-parser.cpp 第 5805 行进入。专用解析例程ParseStruct第 6376 行、ParseClass第 6447 行、parseEnumDecl第 6496 行直接构造对应的 AST 节点。在解析层面class是class与struct中远为狭窄的一个。ParseClass只读取必需的名称、可选继承子句与函数体再无其他。ParseStruct额外接受匿名形式后面没有标识符时合成名字、通过parseOptGenericDecl解析的泛型参数列表、无体的前向声明struct S;以及别名形式struct S T;——因此泛型聚合类型必须写成struct因为ParseClass没有任何路径消费泛型参数列表。除此之外解析器不区分二者它构建ClassDecl而非StructDecl把该选择的所有语义后果留给后续阶段见 pipeline/03-semantic-check.md。同一个类型说明符解析器还通过直接标识符前视识别变长参数包类型形式expand与eachslang-parser.cpp 第 3446-3455 行旁边是__first/__last/__trimFirst/__trimLast/__shapeConcat/__shapePermute/__shapeSwap/__shapeReduce/__packBranch形状工具列于表达式关键字一节这些同样不在g_parseSyntaxEntries[]中。紧接其后同一链在第 3476 行接受functype交给parseFuncTypeExpr第 3261 行解析函数类型它也是按前视匹配而非注册为语法。拼写为functype(parameter types) - result type——零个或多个逗号分隔的参数类型表达式、一个必需的-与一个结果类型。核心模块用它表示高阶参数如 hlsl.meta.slang 中的This MapElement(functype(uint32_t, uint32_t, T) - T mapOp)此类参数接受一个函数名作为实参。泛型参数列表接受同一关键字的functype F形式以声明函数类型的泛型参数。修饰符关键字修饰符关键字通过_makeParseModifier注册于 slang-parser.cpp。部分为简单修饰符单个关键字、单个 AST 节点类部分带参数如layout、__target_intrinsic。简单修饰符关键字AST 节点inInModifieroutOutModifierinoutInOutModifier__refRefModifier__constrefBorrowModifierconstConstModifier__builtinBuiltinModifierhighp,lowp,mediumpGLSLPrecisionModifier__globalActualGlobalModifierinlineInlineModifierpublic,private,internalPublicModifier,PrivateModifier,InternalModifierrequireRequireModifierparamParamModifierexternExternModifierdynDynModifierrow_major,column_majorHLSLRowMajorLayoutModifier,HLSLColumnMajorLayoutModifiernointerpolation,noperspective,linear,sample,centroid,precise插值修饰符groupsharedHLSLGroupSharedModifierstaticHLSLStaticModifieruniformHLSLUniformModifierexportHLSLExportModifierdynamic_uniformDynamicUniformModifieroverrideOverrideModifierpoint,line,triangle,lineadj,triangleadj几何着色器输入修饰符vertices,indices,primitives,payload网格着色器输出修饰符__prefix,__postfix一元运算符位置修饰符__exported再导出import修饰符上表每一行都以_makeParseModifier(keyword, getSyntaxClass...())重载注册其回调为parseSimpleSyntax构造该类的实例且不读取任何后续 token。因此该关键字的全部解析期含义就是第二列中的节点关于它所附着声明的一切在此处都不做检查。各节点类后续意味着什么按节点类记录在 ast-reference/modifiers.md——读者应到该页而非本页查找row_major或nointerpolation这类修饰符的用户可观察效果。回调解析的修饰符部分带参数关键字解析内容sharedparseSharedModifier在上下文上设置 HLSL groupshared / sharedvolatileparseVolatileModifiercoherentparseCoherentModifierrestrictparseRestrictModifierreadonlyparseReadonlyModifierwriteonlyparseWriteonlyModifierlayoutparseLayoutModifierGLSL 风格 layout 块hitAttributeEXTparseHitAttributeEXTModifier光线追踪__intrinsic_opparseIntrinsicOpModifier__target_intrinsicparseTargetIntrinsicModifier__specialized_for_targetparseSpecializedForTargetModifier__glsl_extensionparseGLSLExtensionModifier__glsl_versionparseGLSLVersionModifier__spirv_versionparseSPIRVVersionModifier__wgsl_extensionparseWGSLExtensionModifier__cuda_sm_versionparseCUDASMVersionModifier__builtin_typeparseBuiltinTypeModifier__builtin_requirementparseBuiltinRequirementModifier__magic_typeparseMagicTypeModifier__magic_enumparseMagicEnumModifier__intrinsic_typeparseIntrinsicTypeModifier__implicit_conversionparseImplicitConversionModifier__attributeTargetparseAttributeTargetModifier哪些形式真正带参数由回调决定而非由表格标题决定。其中六个不读取任何 tokenshared、volatile、coherent、restrict、readonly与writeonly均裸写其回调存在是为了选择或复制节点而非解析操作数——shared在解析器的allowGLSLInput选项开启时构建HLSLGroupSharedModifier否则构建HLSLEffectSharedModifiervolatile同时构建 HLSL 与 GLSL 节点并从语言版本 2025 起将关键字诊断为弃用、2026 起移除。hitAttributeEXT同样不带参数。layout接受一个圆括号括起的逗号分隔 GLSL 限定符列表每项为裸名称或name expr如layout(local_size_x 8, std430)。其余__前缀行接受圆括号参数列表__glsl_extension(GL_KHR_shader_subgroup_basic)、__wgsl_extension(subgroups)、__specialized_for_target(glsl)、__attributeTarget(SyntaxClass)接受标识符__glsl_version(430)、__builtin_type(tag)、__builtin_requirement(kind)接受整数__spirv_version(1.3)、__cuda_sm_version(7.0)接受major.minor或带引号版本__magic_type(Name[, tag])、__magic_enum接受带可选标签的名字__intrinsic_type(op[, operand]...)接受 IR 操作码加可选整数操作数__target_intrinsic(hlsl, ...)接受目标名加可选定义。其中四个仅在可选情况下接受圆括号没有圆括号也各有含义裸__intrinsic_op从函数名推导操作码而非接受它否则可接受的整数或标识符__target_intrinsic、__specialized_for_target与__implicit_conversion在无括号时回退到默认值。表达式关键字表达式关键字通过_makeParseExpr注册于 slang-parser.cpp关键字解析内容this自引用parseThisExprtrue,false布尔字面量nullptr空指针字面量noneOptional的 none 字面量try错误处理表达式parseTryExprno_diff不可微包装parseTreatAsDifferentiableExpr__fwd_diff,fwd_diff前向模式微分parseForwardDifferentiate__bwd_diff,bwd_diff反向模式微分parseBackwardDifferentiate__apply反向高阶应用表达式parseApplyForBwd用于__func_extension内部为自定义bwd_diff暴露 primal-with-context 伴生函数实验特性new堆式分配表达式由parsePrefixExpr的AdvanceIf(parser, new)分支特殊解析slang-parser.cppparsePrefixExpr定义于第 9703 行不经由_makeParseExpr__return_val编译器内部返回值引用__func_as_type函数即类型的反射__dispatch_kernel内核分派原语sizeof,alignof,countof大小 / 对齐 / 元素个数查询__first,__last,__trimFirst,__trimLast,__shapeConcat,__shapePermute,__shapeSwap,__shapeReduce,__packBranch形状 / 打包工具表达式__getAddress编译器内部取地址__floatAsInt编译器内部位重解释每一行的操作数形态由回调固定且大多数并非全部行带圆括号try与no_diff后接一个叶子表达式自身不带圆括号——try f(x)、no_diff f(x)。__return_val完全不带操作数它是对待返回值的裸引用。fwd_diff/__fwd_diff、bwd_diff/__bwd_diff、__apply、__func_as_type、__getAddress、__floatAsInt与countof恰好接受一个圆括号操作数——fwd_diff(f)、countof(pack)。sizeof与alignof接受一个操作数加可选第二个数据布局操作数sizeof(T)或sizeof(T, Std140DataLayout)。__first、__last、__trimFirst、__trimLast接受一个 pack 操作数__shapePermute与__shapeReduce接受两个__shapeConcat、__shapeSwap、__packBranch接受三个__packBranch(pack, empty type, non-empty type)。__dispatch_kernel(function, dispatch size, thread-group size)接受三个。new是作用于后缀表达式的前缀运算符写作new T(args)——先解析类型名及其实参列表再折叠进NewExpr。核心模块的语法声明位于 source/slang 的四个*.meta.slang文件为默认环境贡献了额外名字。它们在解析器语法表的意义上不是关键字解析器的语法查找只接受SyntaxDecl因此这些名字是解析器在进行有限类型名消歧时查阅的内置词汇而非解析关键字。处理要点core.meta.slang 声明内置标量 / 向量 / 矩阵类型、Optional与Tuple类型以及核心内在函数。hlsl.meta.slang 叠加 HLSL 兼容名Texture2D、RWTexture2D、StructuredBuffermul、dot、length等内在函数以及 wave 内在函数。此处的两种wave builtin并不可互换。WaveGetWaveIndex()是普通的核心模块函数它带有[require(cuda_glsl_hlsl_metal_spirv_wgsl, subgroup_workgroup_index)]与一个每目标一个分支的__target_switch函数体其可用性在模块自身中即已声明。SV_WaveIndex与SV_GroupIndex则不是函数而是系统值语义写在文件顶部附近的隐藏in全局变量__builtinWaveIndex与__builtinGroupIndex的:之后模块未给它们附加任何能力需求哪些目标接受它们由入口点可变参数合法化pipeline/05-ir-passes.md决定而非在此处。因此WaveGetWaveIndex()才是可移植的拼写。同一文件声明描述符堆词汇——UntypedResourceHandle与UntypedSamplerHandle连同__ResourceDescriptorHeapType/__SamplerDescriptorHeapType类型其__subscript把索引变为句柄——每个都由[require(glsl_hlsl_spirv_wgsl, descriptor_handle)]门控使不支持的 target 在下标处即被诊断。这两个类型的用户级拼写是一对static const全局量ResourceDescriptorHeap与SamplerDescriptorHeap因此表层形式是ResourceDescriptorHeap[i]。它产出的无类型句柄并不写下来每个可堆强转的资源类型都声明一个接受句柄的__implicit_conversion构造函数具体类型从赋值目标恢复如RWStructuredBufferuint buf ResourceDescriptorHeap[0];。glsl.meta.slang 提供 GLSL 风格名字vec3、mat4、gl_Position等。diff.meta.slang 贡献自动微分机制使用的微分对类型与辅助函数见 pipeline/05-ir-passes.md。核心模块流水线的整体描述见 cross-cutting/core-module.md。保留标识符前缀按约定以__开头的名字如__intrinsic_op、__target_intrinsic、__init、__subscript、__import、__include、__constraint、__file_decl表示用户代码不应依赖的编译器内部词汇。少数具有无下划线的解析器注册公开拼写extension、import__init、__subscript与__include在g_parseSyntaxEntries[]中没有无下划线拼写。以gl_开头的名字来自 GLSL 元模块表示着色器阶段内建量。它们是普通全局声明——public out float4 gl_Position : SV_Position;——而非词汇类。以SV_开头的名字HLSL 系统值语义以语义字符串而非关键字形式出现它们在语义检查期间被识别pipeline/03-semantic-check.md。禁用 / 保留集合并非在词法上强制而是由元模块编码的策略。两个前缀都是建议性的背后没有任何诊断支撑因此用户声明一个以此开头的名字就是普通声明。解析器仅在一处检查gl_前缀——名称以gl_开头的 GLSL 接口块被视为内建块的重声明替换为EmptyDecl——并且从不检查SV_。解析器唯一的保留名检查是isReservedKeywordNameslang-parser.cpp当声明符命名为struct、class、enum、typealias或typedef时发出警告KeywordUsedAsName——这五个拼写会开启一个类型说明符因此与其中一个重名的名字无法在语句开头被引用。其注释陈述了其余词汇遵守的规则几乎每个关键字都是上下文相关的可被用户定义的名字遮蔽包括func、let、var、interface、extension、import等声明关键字。__前缀是真正承重的前缀而且只对上述表格列出的确切拼写承重。只有__init、__subscript与__include的__前缀形式注册于g_parseSyntaxEntries[]裸init、subscript、include是普通标识符可用作函数名并在语句开头调用。【免费下载链接】slangMaking it easier to work with shaders项目地址: https://gitcode.com/GitHub_Trending/sl/slang创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考