8. Formal Language Grammar#

This section gives the complete syntax of OSL. Syntactic structures that have a name ending in -opt are optional. Structures surrounded by curly braces { } may be repeated 0 or more times. Text in typewriter face indicates literal text. The \(\epsilon\) character is used to indicate that it is acceptable for there to be nothing (empty, no token).

8.1. Lexical elements#

<digit> ::= “0” | “1” | “2” | “3” | “4” | “5” | “6” | “7” | “8” | “9

<digit-sequence> ::= <digit> { <digit> }

<hexdigit> ::= <digit> | “a” | “A” | “b” | “B” | “c” | “C” | “d” | “D” | “e” | “E” | “f” | “F

<hexdigit-sequence> ::= <hexdigit> { <hexdigit> }

<integer> ::= <sign> <digit-sequence>
\(~~~~~~~~~~\) | <sign> “0x” <hexdigit-sequence>

<floating-point> ::= <digit-sequence> <decimal-part-opt> <exponent-opt>
\(~~~~~~~~~~\) | <decimal-part> <exponent-opt>

<decimal-part> ::= ‘.’ { <digit> }

<exponent> ::= ‘e’ <sign> <digit-sequence>

<sign> ::= ‘-’ | ‘+’ | \(\epsilon\)

<number> ::= <integer>
\(~~~~~~~~~~\) | <floating-point>

<char-sequence> ::= { <any-char> }

<stringliteral> ::= " <char-sequence> "

<identifier> ::= <letter-or-underscore> { <letter-or-underscore-or-digit> }

8.2. Overall structure#

<shader-file> ::= { <global-declaration> }

<global-declaration> ::= <function-declaration>
\(~~~~~~~~~~\) | <struct-declaration>
\(~~~~~~~~~~\) | <shader-declaration>

<shader-declaration> ::=
\(~~~~~~~~~~~~\) \(~~~~~~~~~~\) <shadertype> <identifier> <metadata-block-opt> “(” <shader-formal-params-opt> “)” “{” <statement-list> “}”

<shadertype> ::= “displacement” | “shader” | “surface” | “volume”

<shader-formal-params> ::= <shader-formal-param> { “,” <shader-formal-param> }

<shader-formal-param> ::= <outputspec> <typespec> <identifier> <initializer> <metadata-block-opt>
\(~~~~~~~~~~\) | <outputspec> <typespec> <identifier> <arrayspec> <initializer-list> <metadata-block-opt>

<metadata-block> ::= “[[” <metadata> { “,” <metadata> } “]]”

<metadata> ::= <simple-typespec> <identifier> <initializer>

8.3. Declarations#

<function-declaration> ::=
\(~~~~~~~~~~~~\) <typespec> <identifier> “(” <function-formal-params-opt> “)” “{” <statement-list> “}”

<function-formal-params> ::= <function-formal-param> { “,” <function-formal-param> }

<function-formal-param> ::= <outputspec> <typespec> <identifier> <arrayspec-opt>

<outputspec> ::= “output” | \(\epsilon\)

<struct-declaration> ::= “struct” <identifier> “{” <field-declarations> “}” “;”

<field-declarations> ::= <field-declaration> { <field-declaration> }

<field-declaration> ::= <typespec> <typed-field-list> “;”

<typed-field-list> ::= <typed-field> { “,” <typed-field> }

<typed-field> ::= <identifier> <arrayspec-opt>

<local-declaration> ::= <function-declaration>
\(~~~~~~~~~~\) | <variable-declaration>

<arrayspec> ::= “[” <integer> “]”
\(~~~~~~~~~~\) | “[” “]”

<variable-declaration> ::= <typespec> <def-expressions> “;”

<def-expressions> ::= <def-expression> { “,” <def-expression> }

<def-expression> ::= <identifier> <initializer-opt>
\(~~~~~~~~~~\) | <identifier> <arrayspec> <initializer-list-opt>

<initializer> ::= “=” <expression>

<initializer-list> ::= “=” <compound-initializer>

<compound-initializer> ::= “{” <init-expression-list> “}”

<init-expression-list> ::= <init-expression> { “,” <init-expression> }

<init-expression> ::= <expression> | <compound-initializer>

<typespec> ::= <simple-typename>
\(~~~~~~~~~~\) | “closure” <simple-typename>
\(~~~~~~~~~~\) | <identifier-structname>

<simple-typename> ::= “color” | “float” | “matrix” | “normal” | “point” | “string” | “vector” | “void”

8.4. Statements#

<statement-list> ::= <statement> { <statement> }

<statement> ::= <compound-expression-opt> “;”
\(~~~~~~~~~~\) | <scoped-statements>
\(~~~~~~~~~~\) | <local-declaration>
\(~~~~~~~~~~\) | <conditional-statement>
\(~~~~~~~~~~\) | <loop-statement>
\(~~~~~~~~~~\) | <loopmod-statement>
\(~~~~~~~~~~\) | <return-statement>

<scoped-statements> ::= “{” <statement-list-opt> “}”

<conditional-statement> ::=
\(~~~~~~~~~~~~\) “if” “(” <compound-expression> “)” <statement>
\(~~~~~~~~~~\) | “if” “(” <compound-expression> “)” <statement> “else” <statement>

<loop-statement> ::=
\(~~~~~~~~~~~~\) “while” “(” <compound-expression> “)” <statement>
\(~~~~~~~~~~\) | “do” <statement> “while” “(” <compound-expression> “)” “;”
\(~~~~~~~~~~\) | “for” “(” <for-init-statement-opt> <compound-expression-opt> “;” <compound-expression-opt> “)” <statement>

<for-init-statement> ::=
\(~~~~~~~~~~~~\) <expression-opt> “;”
\(~~~~~~~~~~\) | <variable-declaration>

<loopmod-statement> ::= “break” “;”
\(~~~~~~~~~~\) | “continue” “;”

<return-statement> ::= “return” <expression-opt> “;”

8.5. Expressions#

<expression-list> ::= <expression> { “,” <expression> }

<expression> ::= <number>
\(~~~~~~~~~~\) | <stringliteral>
\(~~~~~~~~~~\) | <type-constructor>
\(~~~~~~~~~~\) | <incdec-op> <variable-ref>
\(~~~~~~~~~~\) | <expression> <binary-op> <expression>
\(~~~~~~~~~~\) | <unary-op> <expression>
\(~~~~~~~~~~\) | “(” <compound-expression> “)”
\(~~~~~~~~~~\) | <function-call>
\(~~~~~~~~~~\) | <assign-expression>
\(~~~~~~~~~~\) | <ternary-expression>
\(~~~~~~~~~~\) | <typecast-expression>
\(~~~~~~~~~~\) | <variable-ref>
\(~~~~~~~~~~\) | <compound-initializer>

<compound-expression> ::= <expression> { “,” <expression> }

<variable-lvalue> ::= <identifier> <array-deref-opt> <component-deref-opt>
\(~~~~~~~~~~\) | <variable_lvalue> “[” <expression> “]”
\(~~~~~~~~~~\) | <variable_lvalue> “.” <identifier>

<variable-ref> ::= <identifier> <array-deref-opt>

<array-deref> ::= “[” <expression> “]”

<component-deref> ::= “[” <expression> “]”
\(~~~~~~~~~~\) | “.” <component-field>

<component-field> ::= “x” | “y” | “z” | “r” | “g” | “b”

<binary-op> ::= “*” | “/” | “%”
\(~~~~~~~~~~\) | “+” | “-”
\(~~~~~~~~~~\) | “<<” | “>>”
\(~~~~~~~~~~\) | “<” | “<=” | “>” | “>=”
\(~~~~~~~~~~\) | “==” | “!=”
\(~~~~~~~~~~\) | “&”
\(~~~~~~~~~~\) | “^”
\(~~~~~~~~~~\) | “|”
\(~~~~~~~~~~\) | “&&” | “and”
\(~~~~~~~~~~\) | “||” | “or”

<unary-op> ::= “-” | “~” | “!” | “not”

<incdec-op> ::= “++” | “–”

<type-constructor> ::= <typespec> “(” <expression-list> “)”

<function-call> ::= <identifier> “(” <function-args-opt> “)”

<function-args> ::= <expression> { “,” <expression> }

<assign-expression> ::= <variable-lvalue> <assign-op> <expression>

<assign-op> ::= “=” | “*=” | “/=” | “+=” | “-=” | “&=” | “|=” | “^=” | “<<=” | “>>=”

<ternary-expression> ::= <expression> “?” <expression> “:” <expression>

<typecast-expression> ::= “(” <simple-typename> “)” <expression>