summaryrefslogtreecommitdiffstats
path: root/src/compiler/glsl/glcpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/glsl/glcpp')
-rw-r--r--src/compiler/glsl/glcpp/.gitignore6
-rw-r--r--src/compiler/glsl/glcpp/README30
-rw-r--r--src/compiler/glsl/glcpp/glcpp-lex.l577
-rw-r--r--src/compiler/glsl/glcpp/glcpp-parse.y2557
-rw-r--r--src/compiler/glsl/glcpp/glcpp.c182
-rw-r--r--src/compiler/glsl/glcpp/glcpp.h251
-rw-r--r--src/compiler/glsl/glcpp/pp.c241
-rw-r--r--src/compiler/glsl/glcpp/tests/.gitignore4
-rw-r--r--src/compiler/glsl/glcpp/tests/000-content-with-spaces.c1
-rw-r--r--src/compiler/glsl/glcpp/tests/000-content-with-spaces.c.expected1
-rw-r--r--src/compiler/glsl/glcpp/tests/001-define.c2
-rw-r--r--src/compiler/glsl/glcpp/tests/001-define.c.expected2
-rw-r--r--src/compiler/glsl/glcpp/tests/002-define-chain.c3
-rw-r--r--src/compiler/glsl/glcpp/tests/002-define-chain.c.expected3
-rw-r--r--src/compiler/glsl/glcpp/tests/003-define-chain-reverse.c3
-rw-r--r--src/compiler/glsl/glcpp/tests/003-define-chain-reverse.c.expected3
-rw-r--r--src/compiler/glsl/glcpp/tests/004-define-recursive.c6
-rw-r--r--src/compiler/glsl/glcpp/tests/004-define-recursive.c.expected6
-rw-r--r--src/compiler/glsl/glcpp/tests/005-define-composite-chain.c3
-rw-r--r--src/compiler/glsl/glcpp/tests/005-define-composite-chain.c.expected3
-rw-r--r--src/compiler/glsl/glcpp/tests/006-define-composite-chain-reverse.c3
-rw-r--r--src/compiler/glsl/glcpp/tests/006-define-composite-chain-reverse.c.expected3
-rw-r--r--src/compiler/glsl/glcpp/tests/007-define-composite-recursive.c6
-rw-r--r--src/compiler/glsl/glcpp/tests/007-define-composite-recursive.c.expected6
-rw-r--r--src/compiler/glsl/glcpp/tests/008-define-empty.c2
-rw-r--r--src/compiler/glsl/glcpp/tests/008-define-empty.c.expected2
-rw-r--r--src/compiler/glsl/glcpp/tests/009-undef.c4
-rw-r--r--src/compiler/glsl/glcpp/tests/009-undef.c.expected4
-rw-r--r--src/compiler/glsl/glcpp/tests/010-undef-re-define.c6
-rw-r--r--src/compiler/glsl/glcpp/tests/010-undef-re-define.c.expected6
-rw-r--r--src/compiler/glsl/glcpp/tests/011-define-func-empty.c2
-rw-r--r--src/compiler/glsl/glcpp/tests/011-define-func-empty.c.expected2
-rw-r--r--src/compiler/glsl/glcpp/tests/012-define-func-no-args.c2
-rw-r--r--src/compiler/glsl/glcpp/tests/012-define-func-no-args.c.expected2
-rw-r--r--src/compiler/glsl/glcpp/tests/013-define-func-1-arg-unused.c2
-rw-r--r--src/compiler/glsl/glcpp/tests/013-define-func-1-arg-unused.c.expected2
-rw-r--r--src/compiler/glsl/glcpp/tests/014-define-func-2-arg-unused.c2
-rw-r--r--src/compiler/glsl/glcpp/tests/014-define-func-2-arg-unused.c.expected2
-rw-r--r--src/compiler/glsl/glcpp/tests/015-define-object-with-parens.c4
-rw-r--r--src/compiler/glsl/glcpp/tests/015-define-object-with-parens.c.expected4
-rw-r--r--src/compiler/glsl/glcpp/tests/016-define-func-1-arg.c2
-rw-r--r--src/compiler/glsl/glcpp/tests/016-define-func-1-arg.c.expected2
-rw-r--r--src/compiler/glsl/glcpp/tests/017-define-func-2-args.c2
-rw-r--r--src/compiler/glsl/glcpp/tests/017-define-func-2-args.c.expected2
-rw-r--r--src/compiler/glsl/glcpp/tests/018-define-func-macro-as-parameter.c3
-rw-r--r--src/compiler/glsl/glcpp/tests/018-define-func-macro-as-parameter.c.expected3
-rw-r--r--src/compiler/glsl/glcpp/tests/019-define-func-1-arg-multi.c2
-rw-r--r--src/compiler/glsl/glcpp/tests/019-define-func-1-arg-multi.c.expected2
-rw-r--r--src/compiler/glsl/glcpp/tests/020-define-func-2-arg-multi.c2
-rw-r--r--src/compiler/glsl/glcpp/tests/020-define-func-2-arg-multi.c.expected2
-rw-r--r--src/compiler/glsl/glcpp/tests/021-define-func-compose.c3
-rw-r--r--src/compiler/glsl/glcpp/tests/021-define-func-compose.c.expected3
-rw-r--r--src/compiler/glsl/glcpp/tests/022-define-func-arg-with-parens.c2
-rw-r--r--src/compiler/glsl/glcpp/tests/022-define-func-arg-with-parens.c.expected2
-rw-r--r--src/compiler/glsl/glcpp/tests/023-define-extra-whitespace.c8
-rw-r--r--src/compiler/glsl/glcpp/tests/023-define-extra-whitespace.c.expected8
-rw-r--r--src/compiler/glsl/glcpp/tests/024-define-chain-to-self-recursion.c3
-rw-r--r--src/compiler/glsl/glcpp/tests/024-define-chain-to-self-recursion.c.expected3
-rw-r--r--src/compiler/glsl/glcpp/tests/025-func-macro-as-non-macro.c2
-rw-r--r--src/compiler/glsl/glcpp/tests/025-func-macro-as-non-macro.c.expected2
-rw-r--r--src/compiler/glsl/glcpp/tests/026-define-func-extra-newlines.c6
-rw-r--r--src/compiler/glsl/glcpp/tests/026-define-func-extra-newlines.c.expected3
-rw-r--r--src/compiler/glsl/glcpp/tests/027-define-chain-obj-to-func.c3
-rw-r--r--src/compiler/glsl/glcpp/tests/027-define-chain-obj-to-func.c.expected3
-rw-r--r--src/compiler/glsl/glcpp/tests/028-define-chain-obj-to-non-func.c3
-rw-r--r--src/compiler/glsl/glcpp/tests/028-define-chain-obj-to-non-func.c.expected3
-rw-r--r--src/compiler/glsl/glcpp/tests/029-define-chain-obj-to-func-with-args.c3
-rw-r--r--src/compiler/glsl/glcpp/tests/029-define-chain-obj-to-func-with-args.c.expected3
-rw-r--r--src/compiler/glsl/glcpp/tests/030-define-chain-obj-to-func-compose.c4
-rw-r--r--src/compiler/glsl/glcpp/tests/030-define-chain-obj-to-func-compose.c.expected4
-rw-r--r--src/compiler/glsl/glcpp/tests/031-define-chain-func-to-func-compose.c4
-rw-r--r--src/compiler/glsl/glcpp/tests/031-define-chain-func-to-func-compose.c.expected4
-rw-r--r--src/compiler/glsl/glcpp/tests/032-define-func-self-recurse.c2
-rw-r--r--src/compiler/glsl/glcpp/tests/032-define-func-self-recurse.c.expected2
-rw-r--r--src/compiler/glsl/glcpp/tests/033-define-func-self-compose.c2
-rw-r--r--src/compiler/glsl/glcpp/tests/033-define-func-self-compose.c.expected2
-rw-r--r--src/compiler/glsl/glcpp/tests/034-define-func-self-compose-non-func.c2
-rw-r--r--src/compiler/glsl/glcpp/tests/034-define-func-self-compose-non-func.c.expected2
-rw-r--r--src/compiler/glsl/glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c2
-rw-r--r--src/compiler/glsl/glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c.expected2
-rw-r--r--src/compiler/glsl/glcpp/tests/036-define-func-non-macro-multi-token-argument.c3
-rw-r--r--src/compiler/glsl/glcpp/tests/036-define-func-non-macro-multi-token-argument.c.expected3
-rw-r--r--src/compiler/glsl/glcpp/tests/037-finalize-unexpanded-macro.c3
-rw-r--r--src/compiler/glsl/glcpp/tests/037-finalize-unexpanded-macro.c.expected3
-rw-r--r--src/compiler/glsl/glcpp/tests/038-func-arg-with-commas.c2
-rw-r--r--src/compiler/glsl/glcpp/tests/038-func-arg-with-commas.c.expected2
-rw-r--r--src/compiler/glsl/glcpp/tests/039-func-arg-obj-macro-with-comma.c24
-rw-r--r--src/compiler/glsl/glcpp/tests/039-func-arg-obj-macro-with-comma.c.expected26
-rw-r--r--src/compiler/glsl/glcpp/tests/040-token-pasting.c2
-rw-r--r--src/compiler/glsl/glcpp/tests/040-token-pasting.c.expected2
-rw-r--r--src/compiler/glsl/glcpp/tests/041-if-0.c5
-rw-r--r--src/compiler/glsl/glcpp/tests/041-if-0.c.expected5
-rw-r--r--src/compiler/glsl/glcpp/tests/042-if-1.c5
-rw-r--r--src/compiler/glsl/glcpp/tests/042-if-1.c.expected5
-rw-r--r--src/compiler/glsl/glcpp/tests/043-if-0-else.c7
-rw-r--r--src/compiler/glsl/glcpp/tests/043-if-0-else.c.expected7
-rw-r--r--src/compiler/glsl/glcpp/tests/044-if-1-else.c7
-rw-r--r--src/compiler/glsl/glcpp/tests/044-if-1-else.c.expected7
-rw-r--r--src/compiler/glsl/glcpp/tests/045-if-0-elif.c11
-rw-r--r--src/compiler/glsl/glcpp/tests/045-if-0-elif.c.expected11
-rw-r--r--src/compiler/glsl/glcpp/tests/046-if-1-elsif.c11
-rw-r--r--src/compiler/glsl/glcpp/tests/046-if-1-elsif.c.expected11
-rw-r--r--src/compiler/glsl/glcpp/tests/047-if-elif-else.c11
-rw-r--r--src/compiler/glsl/glcpp/tests/047-if-elif-else.c.expected11
-rw-r--r--src/compiler/glsl/glcpp/tests/048-if-nested.c11
-rw-r--r--src/compiler/glsl/glcpp/tests/048-if-nested.c.expected11
-rw-r--r--src/compiler/glsl/glcpp/tests/049-if-expression-precedence.c5
-rw-r--r--src/compiler/glsl/glcpp/tests/049-if-expression-precedence.c.expected5
-rw-r--r--src/compiler/glsl/glcpp/tests/050-if-defined.c17
-rw-r--r--src/compiler/glsl/glcpp/tests/050-if-defined.c.expected17
-rw-r--r--src/compiler/glsl/glcpp/tests/051-if-relational.c35
-rw-r--r--src/compiler/glsl/glcpp/tests/051-if-relational.c.expected35
-rw-r--r--src/compiler/glsl/glcpp/tests/052-if-bitwise.c20
-rw-r--r--src/compiler/glsl/glcpp/tests/052-if-bitwise.c.expected20
-rw-r--r--src/compiler/glsl/glcpp/tests/053-if-divide-and-shift.c15
-rw-r--r--src/compiler/glsl/glcpp/tests/053-if-divide-and-shift.c.expected15
-rw-r--r--src/compiler/glsl/glcpp/tests/054-if-with-macros.c34
-rw-r--r--src/compiler/glsl/glcpp/tests/054-if-with-macros.c.expected34
-rw-r--r--src/compiler/glsl/glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c3
-rw-r--r--src/compiler/glsl/glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c.expected3
-rw-r--r--src/compiler/glsl/glcpp/tests/056-macro-argument-with-comma.c4
-rw-r--r--src/compiler/glsl/glcpp/tests/056-macro-argument-with-comma.c.expected4
-rw-r--r--src/compiler/glsl/glcpp/tests/057-empty-arguments.c6
-rw-r--r--src/compiler/glsl/glcpp/tests/057-empty-arguments.c.expected6
-rw-r--r--src/compiler/glsl/glcpp/tests/058-token-pasting-empty-arguments.c5
-rw-r--r--src/compiler/glsl/glcpp/tests/058-token-pasting-empty-arguments.c.expected5
-rw-r--r--src/compiler/glsl/glcpp/tests/059-token-pasting-integer.c4
-rw-r--r--src/compiler/glsl/glcpp/tests/059-token-pasting-integer.c.expected4
-rw-r--r--src/compiler/glsl/glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c3
-rw-r--r--src/compiler/glsl/glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c.expected3
-rw-r--r--src/compiler/glsl/glcpp/tests/061-define-chain-obj-to-func-multi.c5
-rw-r--r--src/compiler/glsl/glcpp/tests/061-define-chain-obj-to-func-multi.c.expected5
-rw-r--r--src/compiler/glsl/glcpp/tests/062-if-0-skips-garbage.c5
-rw-r--r--src/compiler/glsl/glcpp/tests/062-if-0-skips-garbage.c.expected5
-rw-r--r--src/compiler/glsl/glcpp/tests/063-comments.c20
-rw-r--r--src/compiler/glsl/glcpp/tests/063-comments.c.expected20
-rw-r--r--src/compiler/glsl/glcpp/tests/064-version.c2
-rw-r--r--src/compiler/glsl/glcpp/tests/064-version.c.expected2
-rw-r--r--src/compiler/glsl/glcpp/tests/065-if-defined-parens.c17
-rw-r--r--src/compiler/glsl/glcpp/tests/065-if-defined-parens.c.expected17
-rw-r--r--src/compiler/glsl/glcpp/tests/066-if-nospace-expression.c3
-rw-r--r--src/compiler/glsl/glcpp/tests/066-if-nospace-expression.c.expected3
-rw-r--r--src/compiler/glsl/glcpp/tests/067-nested-ifdef-ifndef.c40
-rw-r--r--src/compiler/glsl/glcpp/tests/067-nested-ifdef-ifndef.c.expected40
-rw-r--r--src/compiler/glsl/glcpp/tests/068-accidental-pasting.c11
-rw-r--r--src/compiler/glsl/glcpp/tests/068-accidental-pasting.c.expected11
-rw-r--r--src/compiler/glsl/glcpp/tests/069-repeated-argument.c2
-rw-r--r--src/compiler/glsl/glcpp/tests/069-repeated-argument.c.expected2
-rw-r--r--src/compiler/glsl/glcpp/tests/070-undefined-macro-in-expression.c5
-rw-r--r--src/compiler/glsl/glcpp/tests/070-undefined-macro-in-expression.c.expected5
-rw-r--r--src/compiler/glsl/glcpp/tests/071-punctuator.c1
-rw-r--r--src/compiler/glsl/glcpp/tests/071-punctuator.c.expected1
-rw-r--r--src/compiler/glsl/glcpp/tests/072-token-pasting-same-line.c2
-rw-r--r--src/compiler/glsl/glcpp/tests/072-token-pasting-same-line.c.expected2
-rw-r--r--src/compiler/glsl/glcpp/tests/073-if-in-ifdef.c4
-rw-r--r--src/compiler/glsl/glcpp/tests/073-if-in-ifdef.c.expected4
-rw-r--r--src/compiler/glsl/glcpp/tests/074-elif-undef.c3
-rw-r--r--src/compiler/glsl/glcpp/tests/074-elif-undef.c.expected3
-rw-r--r--src/compiler/glsl/glcpp/tests/075-elif-elif-undef.c4
-rw-r--r--src/compiler/glsl/glcpp/tests/075-elif-elif-undef.c.expected4
-rw-r--r--src/compiler/glsl/glcpp/tests/076-elif-undef-nested.c5
-rw-r--r--src/compiler/glsl/glcpp/tests/076-elif-undef-nested.c.expected5
-rw-r--r--src/compiler/glsl/glcpp/tests/077-else-without-if.c1
-rw-r--r--src/compiler/glsl/glcpp/tests/077-else-without-if.c.expected3
-rw-r--r--src/compiler/glsl/glcpp/tests/078-elif-without-if.c1
-rw-r--r--src/compiler/glsl/glcpp/tests/078-elif-without-if.c.expected3
-rw-r--r--src/compiler/glsl/glcpp/tests/079-endif-without-if.c1
-rw-r--r--src/compiler/glsl/glcpp/tests/079-endif-without-if.c.expected3
-rw-r--r--src/compiler/glsl/glcpp/tests/080-if-without-expression.c4
-rw-r--r--src/compiler/glsl/glcpp/tests/080-if-without-expression.c.expected5
-rw-r--r--src/compiler/glsl/glcpp/tests/081-elif-without-expression.c3
-rw-r--r--src/compiler/glsl/glcpp/tests/081-elif-without-expression.c.expected4
-rw-r--r--src/compiler/glsl/glcpp/tests/082-invalid-paste.c7
-rw-r--r--src/compiler/glsl/glcpp/tests/082-invalid-paste.c.expected19
-rw-r--r--src/compiler/glsl/glcpp/tests/083-unterminated-if.c2
-rw-r--r--src/compiler/glsl/glcpp/tests/083-unterminated-if.c.expected4
-rw-r--r--src/compiler/glsl/glcpp/tests/084-unbalanced-parentheses.c2
-rw-r--r--src/compiler/glsl/glcpp/tests/084-unbalanced-parentheses.c.expected2
-rw-r--r--src/compiler/glsl/glcpp/tests/085-incorrect-argument-count.c5
-rw-r--r--src/compiler/glsl/glcpp/tests/085-incorrect-argument-count.c.expected11
-rw-r--r--src/compiler/glsl/glcpp/tests/086-reserved-macro-names.c3
-rw-r--r--src/compiler/glsl/glcpp/tests/086-reserved-macro-names.c.expected9
-rw-r--r--src/compiler/glsl/glcpp/tests/087-if-comments.c5
-rw-r--r--src/compiler/glsl/glcpp/tests/087-if-comments.c.expected5
-rw-r--r--src/compiler/glsl/glcpp/tests/088-redefine-macro-legitimate.c5
-rw-r--r--src/compiler/glsl/glcpp/tests/088-redefine-macro-legitimate.c.expected5
-rw-r--r--src/compiler/glsl/glcpp/tests/089-redefine-macro-error.c17
-rw-r--r--src/compiler/glsl/glcpp/tests/089-redefine-macro-error.c.expected29
-rw-r--r--src/compiler/glsl/glcpp/tests/090-hash-error.c1
-rw-r--r--src/compiler/glsl/glcpp/tests/090-hash-error.c.expected1
-rw-r--r--src/compiler/glsl/glcpp/tests/091-hash-line.c14
-rw-r--r--src/compiler/glsl/glcpp/tests/091-hash-line.c.expected14
-rw-r--r--src/compiler/glsl/glcpp/tests/092-redefine-macro-error-2.c5
-rw-r--r--src/compiler/glsl/glcpp/tests/092-redefine-macro-error-2.c.expected9
-rw-r--r--src/compiler/glsl/glcpp/tests/093-divide-by-zero.c2
-rw-r--r--src/compiler/glsl/glcpp/tests/093-divide-by-zero.c.expected3
-rw-r--r--src/compiler/glsl/glcpp/tests/094-divide-by-zero-short-circuit.c13
-rw-r--r--src/compiler/glsl/glcpp/tests/094-divide-by-zero-short-circuit.c.expected14
-rw-r--r--src/compiler/glsl/glcpp/tests/095-recursive-define.c3
-rw-r--r--src/compiler/glsl/glcpp/tests/095-recursive-define.c.expected3
-rw-r--r--src/compiler/glsl/glcpp/tests/096-paste-twice.c3
-rw-r--r--src/compiler/glsl/glcpp/tests/096-paste-twice.c.expected3
-rw-r--r--src/compiler/glsl/glcpp/tests/097-paste-with-non-function-macro.c3
-rw-r--r--src/compiler/glsl/glcpp/tests/097-paste-with-non-function-macro.c.expected3
-rw-r--r--src/compiler/glsl/glcpp/tests/098-elif-undefined.c7
-rw-r--r--src/compiler/glsl/glcpp/tests/098-elif-undefined.c.expected7
-rw-r--r--src/compiler/glsl/glcpp/tests/099-c99-example.c17
-rw-r--r--src/compiler/glsl/glcpp/tests/099-c99-example.c.expected16
-rw-r--r--src/compiler/glsl/glcpp/tests/100-macro-with-colon.c7
-rw-r--r--src/compiler/glsl/glcpp/tests/100-macro-with-colon.c.expected7
-rw-r--r--src/compiler/glsl/glcpp/tests/101-macros-used-twice.c16
-rw-r--r--src/compiler/glsl/glcpp/tests/101-macros-used-twice.c.expected16
-rw-r--r--src/compiler/glsl/glcpp/tests/102-garbage-after-endif.c2
-rw-r--r--src/compiler/glsl/glcpp/tests/102-garbage-after-endif.c.expected2
-rw-r--r--src/compiler/glsl/glcpp/tests/103-garbage-after-else-0.c3
-rw-r--r--src/compiler/glsl/glcpp/tests/103-garbage-after-else-0.c.expected4
-rw-r--r--src/compiler/glsl/glcpp/tests/104-hash-line-followed-by-code.c2
-rw-r--r--src/compiler/glsl/glcpp/tests/104-hash-line-followed-by-code.c.expected2
-rw-r--r--src/compiler/glsl/glcpp/tests/105-multiline-hash-line.c5
-rw-r--r--src/compiler/glsl/glcpp/tests/105-multiline-hash-line.c.expected5
-rw-r--r--src/compiler/glsl/glcpp/tests/106-multiline-hash-if.c6
-rw-r--r--src/compiler/glsl/glcpp/tests/106-multiline-hash-if.c.expected6
-rw-r--r--src/compiler/glsl/glcpp/tests/107-multiline-hash-elif.c7
-rw-r--r--src/compiler/glsl/glcpp/tests/107-multiline-hash-elif.c.expected7
-rw-r--r--src/compiler/glsl/glcpp/tests/108-no-space-after-hash-version.c1
-rw-r--r--src/compiler/glsl/glcpp/tests/108-no-space-after-hash-version.c.expected1
-rw-r--r--src/compiler/glsl/glcpp/tests/109-no-space-after-hash-line.c1
-rw-r--r--src/compiler/glsl/glcpp/tests/109-no-space-after-hash-line.c.expected1
-rw-r--r--src/compiler/glsl/glcpp/tests/110-no-space-digits-after-hash-elif.c3
-rw-r--r--src/compiler/glsl/glcpp/tests/110-no-space-digits-after-hash-elif.c.expected3
-rw-r--r--src/compiler/glsl/glcpp/tests/111-no-space-operator-after-hash-if.c19
-rw-r--r--src/compiler/glsl/glcpp/tests/111-no-space-operator-after-hash-if.c.expected19
-rw-r--r--src/compiler/glsl/glcpp/tests/112-no-space-operator-after-hash-elif.c24
-rw-r--r--src/compiler/glsl/glcpp/tests/112-no-space-operator-after-hash-elif.c.expected24
-rw-r--r--src/compiler/glsl/glcpp/tests/113-line-and-file-macros.c7
-rw-r--r--src/compiler/glsl/glcpp/tests/113-line-and-file-macros.c.expected7
-rw-r--r--src/compiler/glsl/glcpp/tests/114-paste-integer-tokens.c7
-rw-r--r--src/compiler/glsl/glcpp/tests/114-paste-integer-tokens.c.expected7
-rw-r--r--src/compiler/glsl/glcpp/tests/115-line-continuations.c9
-rw-r--r--src/compiler/glsl/glcpp/tests/115-line-continuations.c.expected9
-rw-r--r--src/compiler/glsl/glcpp/tests/116-disable-line-continuations.c13
-rw-r--r--src/compiler/glsl/glcpp/tests/116-disable-line-continuations.c.expected13
-rw-r--r--src/compiler/glsl/glcpp/tests/117-line-continuation-and-non-continuation-backslash.c12
-rw-r--r--src/compiler/glsl/glcpp/tests/117-line-continuation-and-non-continuation-backslash.c.expected12
-rw-r--r--src/compiler/glsl/glcpp/tests/118-comment-becomes-space.c4
-rw-r--r--src/compiler/glsl/glcpp/tests/118-comment-becomes-space.c.expected4
-rw-r--r--src/compiler/glsl/glcpp/tests/119-elif-after-else.c6
-rw-r--r--src/compiler/glsl/glcpp/tests/119-elif-after-else.c.expected7
-rw-r--r--src/compiler/glsl/glcpp/tests/120-undef-builtin.c3
-rw-r--r--src/compiler/glsl/glcpp/tests/120-undef-builtin.c.expected6
-rw-r--r--src/compiler/glsl/glcpp/tests/121-comment-bug-72686.c2
-rw-r--r--src/compiler/glsl/glcpp/tests/121-comment-bug-72686.c.expected2
-rw-r--r--src/compiler/glsl/glcpp/tests/122-redefine-whitespace.c16
-rw-r--r--src/compiler/glsl/glcpp/tests/122-redefine-whitespace.c.expected22
-rw-r--r--src/compiler/glsl/glcpp/tests/123-garbage-after-else-1.c3
-rw-r--r--src/compiler/glsl/glcpp/tests/123-garbage-after-else-1.c.expected4
-rw-r--r--src/compiler/glsl/glcpp/tests/124-preprocessing-numbers.c37
-rw-r--r--src/compiler/glsl/glcpp/tests/124-preprocessing-numbers.c.expected37
-rw-r--r--src/compiler/glsl/glcpp/tests/125-es-short-circuit-undefined.c27
-rw-r--r--src/compiler/glsl/glcpp/tests/125-es-short-circuit-undefined.c.expected29
-rw-r--r--src/compiler/glsl/glcpp/tests/126-garbage-after-directive.c5
-rw-r--r--src/compiler/glsl/glcpp/tests/126-garbage-after-directive.c.expected7
-rw-r--r--src/compiler/glsl/glcpp/tests/127-pragma-empty.c3
-rw-r--r--src/compiler/glsl/glcpp/tests/127-pragma-empty.c.expected3
-rw-r--r--src/compiler/glsl/glcpp/tests/128-space-before-hash.c21
-rw-r--r--src/compiler/glsl/glcpp/tests/128-space-before-hash.c.expected21
-rw-r--r--src/compiler/glsl/glcpp/tests/129-define-non-identifier.c1
-rw-r--r--src/compiler/glsl/glcpp/tests/129-define-non-identifier.c.expected2
-rw-r--r--src/compiler/glsl/glcpp/tests/130-define-comment.c2
-rw-r--r--src/compiler/glsl/glcpp/tests/130-define-comment.c.expected2
-rw-r--r--src/compiler/glsl/glcpp/tests/131-eof-without-newline.c1
-rw-r--r--src/compiler/glsl/glcpp/tests/131-eof-without-newline.c.expected1
-rw-r--r--src/compiler/glsl/glcpp/tests/132-eof-without-newline-define.c1
-rw-r--r--src/compiler/glsl/glcpp/tests/132-eof-without-newline-define.c.expected1
-rw-r--r--src/compiler/glsl/glcpp/tests/133-eof-without-newline-comment.c1
-rw-r--r--src/compiler/glsl/glcpp/tests/133-eof-without-newline-comment.c.expected2
-rw-r--r--src/compiler/glsl/glcpp/tests/134-hash-comment-directive.c22
-rw-r--r--src/compiler/glsl/glcpp/tests/134-hash-comment-directive.c.expected22
-rw-r--r--src/compiler/glsl/glcpp/tests/135-duplicate-parameter.c2
-rw-r--r--src/compiler/glsl/glcpp/tests/135-duplicate-parameter.c.expected4
-rw-r--r--src/compiler/glsl/glcpp/tests/136-plus-plus-and-minus-minus.c8
-rw-r--r--src/compiler/glsl/glcpp/tests/136-plus-plus-and-minus-minus.c.expected8
-rw-r--r--src/compiler/glsl/glcpp/tests/137-expand-macro-after-period.c4
-rw-r--r--src/compiler/glsl/glcpp/tests/137-expand-macro-after-period.c.expected4
-rw-r--r--src/compiler/glsl/glcpp/tests/138-multi-line-comment-in-if-0.c7
-rw-r--r--src/compiler/glsl/glcpp/tests/138-multi-line-comment-in-if-0.c.expected7
-rw-r--r--src/compiler/glsl/glcpp/tests/139-define-without-macro-name.c5
-rw-r--r--src/compiler/glsl/glcpp/tests/139-define-without-macro-name.c.expected5
-rw-r--r--src/compiler/glsl/glcpp/tests/140-null-directive.c9
-rw-r--r--src/compiler/glsl/glcpp/tests/140-null-directive.c.expected9
-rw-r--r--src/compiler/glsl/glcpp/tests/141-pragma-and-__LINE__.c6
-rw-r--r--src/compiler/glsl/glcpp/tests/141-pragma-and-__LINE__.c.expected6
-rw-r--r--src/compiler/glsl/glcpp/tests/142-defined-within-macro.c94
-rw-r--r--src/compiler/glsl/glcpp/tests/142-defined-within-macro.c.expected94
-rw-r--r--src/compiler/glsl/glcpp/tests/143-multiple-else.c6
-rw-r--r--src/compiler/glsl/glcpp/tests/143-multiple-else.c.expected7
-rwxr-xr-xsrc/compiler/glsl/glcpp/tests/glcpp-test110
-rwxr-xr-xsrc/compiler/glsl/glcpp/tests/glcpp-test-cr-lf141
298 files changed, 6284 insertions, 0 deletions
diff --git a/src/compiler/glsl/glcpp/.gitignore b/src/compiler/glsl/glcpp/.gitignore
new file mode 100644
index 00000000000..24a7119caa4
--- /dev/null
+++ b/src/compiler/glsl/glcpp/.gitignore
@@ -0,0 +1,6 @@
+glcpp
+glcpp-lex.c
+glcpp-parse.output
+glcpp-parse.c
+glcpp-parse.h
+tests/*.out
diff --git a/src/compiler/glsl/glcpp/README b/src/compiler/glsl/glcpp/README
new file mode 100644
index 00000000000..0637935e28b
--- /dev/null
+++ b/src/compiler/glsl/glcpp/README
@@ -0,0 +1,30 @@
+glcpp -- GLSL "C" preprocessor
+
+This is a simple preprocessor designed to provide the preprocessing
+needs of the GLSL language. The requirements for this preprocessor are
+specified in the GLSL 1.30 specification availble from:
+
+http://www.opengl.org/registry/doc/GLSLangSpec.Full.1.30.10.pdf
+
+This specification is not precise on some semantics, (for example,
+#define and #if), defining these merely "as is standard for C++
+preprocessors". To fill in these details, I've been using a draft of
+the C99 standard as available from:
+
+http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf
+
+Any downstream compiler accepting output from glcpp should be prepared
+to encounter and deal with the following preprocessor macros:
+
+ #line
+ #pragma
+ #extension
+
+All other macros will be handled according to the GLSL specification
+and will not appear in the output.
+
+Known limitations
+-----------------
+A file that ends with a function-like macro name as the last
+non-whitespace token will result in a parse error, (where it should be
+passed through as is). \ No newline at end of file
diff --git a/src/compiler/glsl/glcpp/glcpp-lex.l b/src/compiler/glsl/glcpp/glcpp-lex.l
new file mode 100644
index 00000000000..fa9aa506912
--- /dev/null
+++ b/src/compiler/glsl/glcpp/glcpp-lex.l
@@ -0,0 +1,577 @@
+%{
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "glcpp.h"
+#include "glcpp-parse.h"
+
+/* Flex annoyingly generates some functions without making them
+ * static. Let's declare them here. */
+int glcpp_get_column (yyscan_t yyscanner);
+void glcpp_set_column (int column_no , yyscan_t yyscanner);
+
+#ifdef _MSC_VER
+#define YY_NO_UNISTD_H
+#endif
+
+#define YY_NO_INPUT
+
+#define YY_USER_ACTION \
+ do { \
+ if (parser->has_new_line_number) \
+ yylineno = parser->new_line_number; \
+ if (parser->has_new_source_number) \
+ yylloc->source = parser->new_source_number; \
+ yylloc->first_column = yycolumn + 1; \
+ yylloc->first_line = yylloc->last_line = yylineno; \
+ yycolumn += yyleng; \
+ yylloc->last_column = yycolumn + 1; \
+ parser->has_new_line_number = 0; \
+ parser->has_new_source_number = 0; \
+ } while(0);
+
+#define YY_USER_INIT \
+ do { \
+ yylineno = 1; \
+ yycolumn = 0; \
+ yylloc->source = 0; \
+ } while(0)
+
+/* It's ugly to have macros that have return statements inside of
+ * them, but flex-based lexer generation is all built around the
+ * return statement.
+ *
+ * To mitigate the ugliness, we defer as much of the logic as possible
+ * to an actual function, not a macro (see
+ * glcpplex_update_state_per_token) and we make the word RETURN
+ * prominent in all of the macros which may return.
+ *
+ * The most-commonly-used macro is RETURN_TOKEN which will perform all
+ * necessary state updates based on the provided token,, then
+ * conditionally return the token. It will not return a token if the
+ * parser is currently skipping tokens, (such as within #if
+ * 0...#else).
+ *
+ * The RETURN_TOKEN_NEVER_SKIP macro is a lower-level variant that
+ * makes the token returning unconditional. This is needed for things
+ * like #if and the tokens of its condition, (since these must be
+ * evaluated by the parser even when otherwise skipping).
+ *
+ * Finally, RETURN_STRING_TOKEN is a simple convenience wrapper on top
+ * of RETURN_TOKEN that performs a string copy of yytext before the
+ * return.
+ */
+#define RETURN_TOKEN_NEVER_SKIP(token) \
+ do { \
+ if (glcpp_lex_update_state_per_token (parser, token)) \
+ return token; \
+ } while (0)
+
+#define RETURN_TOKEN(token) \
+ do { \
+ if (! parser->skipping) { \
+ RETURN_TOKEN_NEVER_SKIP(token); \
+ } \
+ } while(0)
+
+#define RETURN_STRING_TOKEN(token) \
+ do { \
+ if (! parser->skipping) { \
+ yylval->str = ralloc_strdup (yyextra, yytext); \
+ RETURN_TOKEN_NEVER_SKIP (token); \
+ } \
+ } while(0)
+
+
+/* Update all state necessary for each token being returned.
+ *
+ * Here we'll be tracking newlines and spaces so that the lexer can
+ * alter its behavior as necessary, (for example, '#' has special
+ * significance if it is the first non-whitespace, non-comment token
+ * in a line, but does not otherwise).
+ *
+ * NOTE: If this function returns FALSE, then no token should be
+ * returned at all. This is used to suprress duplicate SPACE tokens.
+ */
+static int
+glcpp_lex_update_state_per_token (glcpp_parser_t *parser, int token)
+{
+ /* After the first non-space token in a line, we won't
+ * allow any '#' to introduce a directive. */
+ if (token == NEWLINE) {
+ parser->first_non_space_token_this_line = 1;
+ } else if (token != SPACE) {
+ parser->first_non_space_token_this_line = 0;
+ }
+
+ /* Track newlines just to know whether a newline needs
+ * to be inserted if end-of-file comes early. */
+ if (token == NEWLINE) {
+ parser->last_token_was_newline = 1;
+ } else {
+ parser->last_token_was_newline = 0;
+ }
+
+ /* Track spaces to avoid emitting multiple SPACE
+ * tokens in a row. */
+ if (token == SPACE) {
+ if (! parser->last_token_was_space) {
+ parser->last_token_was_space = 1;
+ return 1;
+ } else {
+ parser->last_token_was_space = 1;
+ return 0;
+ }
+ } else {
+ parser->last_token_was_space = 0;
+ return 1;
+ }
+}
+
+
+%}
+
+%option bison-bridge bison-locations reentrant noyywrap
+%option extra-type="glcpp_parser_t *"
+%option prefix="glcpp_"
+%option stack
+%option never-interactive
+%option warn nodefault
+
+ /* Note: When adding any start conditions to this list, you must also
+ * update the "Internal compiler error" catch-all rule near the end of
+ * this file. */
+
+%x COMMENT DEFINE DONE HASH NEWLINE_CATCHUP UNREACHABLE
+
+SPACE [[:space:]]
+NONSPACE [^[:space:]]
+HSPACE [ \t]
+HASH #
+NEWLINE (\r\n|\n\r|\r|\n)
+IDENTIFIER [_a-zA-Z][_a-zA-Z0-9]*
+PP_NUMBER [.]?[0-9]([._a-zA-Z0-9]|[eEpP][-+])*
+PUNCTUATION [][(){}.&*~!/%<>^|;,=+-]
+
+/* The OTHER class is simply a catch-all for things that the CPP
+parser just doesn't care about. Since flex regular expressions that
+match longer strings take priority over those matching shorter
+strings, we have to be careful to avoid OTHER matching and hiding
+something that CPP does care about. So we simply exclude all
+characters that appear in any other expressions. */
+
+OTHER [^][_#[:space:]#a-zA-Z0-9(){}.&*~!/%<>^|;,=+-]
+
+DIGITS [0-9][0-9]*
+DECIMAL_INTEGER [1-9][0-9]*[uU]?
+OCTAL_INTEGER 0[0-7]*[uU]?
+HEXADECIMAL_INTEGER 0[xX][0-9a-fA-F]+[uU]?
+
+%%
+
+ glcpp_parser_t *parser = yyextra;
+
+ /* When we lex a multi-line comment, we replace it (as
+ * specified) with a single space. But if the comment spanned
+ * multiple lines, then subsequent parsing stages will not
+ * count correct line numbers. To avoid this problem we keep
+ * track of all newlines that were commented out by a
+ * multi-line comment, and we emit a NEWLINE token for each at
+ * the next legal opportunity, (which is when the lexer would
+ * be emitting a NEWLINE token anyway).
+ */
+ if (YY_START == NEWLINE_CATCHUP) {
+ if (parser->commented_newlines)
+ parser->commented_newlines--;
+ if (parser->commented_newlines == 0)
+ BEGIN INITIAL;
+ RETURN_TOKEN_NEVER_SKIP (NEWLINE);
+ }
+
+ /* Set up the parser->skipping bit here before doing any lexing.
+ *
+ * This bit controls whether tokens are skipped, (as implemented by
+ * RETURN_TOKEN), such as between "#if 0" and "#endif".
+ *
+ * The parser maintains a skip_stack indicating whether we should be
+ * skipping, (and nested levels of #if/#ifdef/#ifndef/#endif) will
+ * push and pop items from the stack.
+ *
+ * Here are the rules for determining whether we are skipping:
+ *
+ * 1. If the skip stack is NULL, we are outside of all #if blocks
+ * and we are not skipping.
+ *
+ * 2. If the skip stack is non-NULL, the type of the top node in
+ * the stack determines whether to skip. A type of
+ * SKIP_NO_SKIP is used for blocks wheere we are emitting
+ * tokens, (such as between #if 1 and #endif, or after the
+ * #else of an #if 0, etc.).
+ *
+ * 3. The lexing_directive bit overrides the skip stack. This bit
+ * is set when we are actively lexing the expression for a
+ * pre-processor condition, (such as #if, #elif, or #else). In
+ * this case, even if otherwise skipping, we need to emit the
+ * tokens for this condition so that the parser can evaluate
+ * the expression. (For, #else, there's no expression, but we
+ * emit tokens so the parser can generate a nice error message
+ * if there are any tokens here).
+ */
+ if (parser->skip_stack &&
+ parser->skip_stack->type != SKIP_NO_SKIP &&
+ ! parser->lexing_directive)
+ {
+ parser->skipping = 1;
+ } else {
+ parser->skipping = 0;
+ }
+
+ /* Single-line comments */
+<INITIAL,DEFINE,HASH>"//"[^\r\n]* {
+}
+
+ /* Multi-line comments */
+<INITIAL,DEFINE,HASH>"/*" { yy_push_state(COMMENT, yyscanner); }
+<COMMENT>[^*\r\n]*
+<COMMENT>[^*\r\n]*{NEWLINE} { yylineno++; yycolumn = 0; parser->commented_newlines++; }
+<COMMENT>"*"+[^*/\r\n]*
+<COMMENT>"*"+[^*/\r\n]*{NEWLINE} { yylineno++; yycolumn = 0; parser->commented_newlines++; }
+<COMMENT>"*"+"/" {
+ yy_pop_state(yyscanner);
+ /* In the <HASH> start condition, we don't want any SPACE token. */
+ if (yyextra->space_tokens && YY_START != HASH)
+ RETURN_TOKEN (SPACE);
+}
+
+{HASH} {
+
+ /* If the '#' is the first non-whitespace, non-comment token on this
+ * line, then it introduces a directive, switch to the <HASH> start
+ * condition.
+ *
+ * Otherwise, this is just punctuation, so return the HASH_TOKEN
+ * token. */
+ if (parser->first_non_space_token_this_line) {
+ BEGIN HASH;
+ }
+
+ RETURN_TOKEN_NEVER_SKIP (HASH_TOKEN);
+}
+
+<HASH>version{HSPACE}+ {
+ BEGIN INITIAL;
+ yyextra->space_tokens = 0;
+ RETURN_STRING_TOKEN (VERSION_TOKEN);
+}
+
+ /* Swallow empty #pragma directives, (to avoid confusing the
+ * downstream compiler).
+ *
+ * Note: We use a simple regular expression for the lookahead
+ * here. Specifically, we cannot use the complete {NEWLINE} expression
+ * since it uses alternation and we've found that there's a flex bug
+ * where using alternation in the lookahead portion of a pattern
+ * triggers a buffer overrun. */
+<HASH>pragma{HSPACE}*/[\r\n] {
+ BEGIN INITIAL;
+}
+
+ /* glcpp doesn't handle #extension, #version, or #pragma directives.
+ * Simply pass them through to the main compiler's lexer/parser. */
+<HASH>(extension|pragma)[^\r\n]* {
+ BEGIN INITIAL;
+ RETURN_STRING_TOKEN (PRAGMA);
+}
+
+<HASH>line{HSPACE}+ {
+ BEGIN INITIAL;
+ RETURN_TOKEN (LINE);
+}
+
+<HASH>{NEWLINE} {
+ BEGIN INITIAL;
+ RETURN_TOKEN_NEVER_SKIP (NEWLINE);
+}
+
+ /* For the pre-processor directives, we return these tokens
+ * even when we are otherwise skipping. */
+<HASH>ifdef {
+ BEGIN INITIAL;
+ yyextra->lexing_directive = 1;
+ yyextra->space_tokens = 0;
+ RETURN_TOKEN_NEVER_SKIP (IFDEF);
+}
+
+<HASH>ifndef {
+ BEGIN INITIAL;
+ yyextra->lexing_directive = 1;
+ yyextra->space_tokens = 0;
+ RETURN_TOKEN_NEVER_SKIP (IFNDEF);
+}
+
+<HASH>if/[^_a-zA-Z0-9] {
+ BEGIN INITIAL;
+ yyextra->lexing_directive = 1;
+ yyextra->space_tokens = 0;
+ RETURN_TOKEN_NEVER_SKIP (IF);
+}
+
+<HASH>elif/[^_a-zA-Z0-9] {
+ BEGIN INITIAL;
+ yyextra->lexing_directive = 1;
+ yyextra->space_tokens = 0;
+ RETURN_TOKEN_NEVER_SKIP (ELIF);
+}
+
+<HASH>else {
+ BEGIN INITIAL;
+ yyextra->space_tokens = 0;
+ RETURN_TOKEN_NEVER_SKIP (ELSE);
+}
+
+<HASH>endif {
+ BEGIN INITIAL;
+ yyextra->space_tokens = 0;
+ RETURN_TOKEN_NEVER_SKIP (ENDIF);
+}
+
+<HASH>error[^\r\n]* {
+ BEGIN INITIAL;
+ RETURN_STRING_TOKEN (ERROR_TOKEN);
+}
+
+ /* After we see a "#define" we enter the <DEFINE> start state
+ * for the lexer. Within <DEFINE> we are looking for the first
+ * identifier and specifically checking whether the identifier
+ * is followed by a '(' or not, (to lex either a
+ * FUNC_IDENTIFIER or an OBJ_IDENITIFIER token).
+ *
+ * While in the <DEFINE> state we also need to explicitly
+ * handle a few other things that may appear before the
+ * identifier:
+ *
+ * * Comments, (handled above with the main support for
+ * comments).
+ *
+ * * Whitespace (simply ignored)
+ *
+ * * Anything else, (not an identifier, not a comment,
+ * and not whitespace). This will generate an error.
+ */
+<HASH>define{HSPACE}* {
+ if (! parser->skipping) {
+ BEGIN DEFINE;
+ yyextra->space_tokens = 0;
+ RETURN_TOKEN (DEFINE_TOKEN);
+ }
+}
+
+<HASH>undef {
+ BEGIN INITIAL;
+ yyextra->space_tokens = 0;
+ RETURN_TOKEN (UNDEF);
+}
+
+<HASH>{HSPACE}+ {
+ /* Nothing to do here. Importantly, don't leave the <HASH>
+ * start condition, since it's legal to have space between the
+ * '#' and the directive.. */
+}
+
+ /* This will catch any non-directive garbage after a HASH */
+<HASH>{NONSPACE} {
+ BEGIN INITIAL;
+ RETURN_TOKEN (GARBAGE);
+}
+
+ /* An identifier immediately followed by '(' */
+<DEFINE>{IDENTIFIER}/"(" {
+ BEGIN INITIAL;
+ RETURN_STRING_TOKEN (FUNC_IDENTIFIER);
+}
+
+ /* An identifier not immediately followed by '(' */
+<DEFINE>{IDENTIFIER} {
+ BEGIN INITIAL;
+ RETURN_STRING_TOKEN (OBJ_IDENTIFIER);
+}
+
+ /* Whitespace */
+<DEFINE>{HSPACE}+ {
+ /* Just ignore it. Nothing to do here. */
+}
+
+ /* '/' not followed by '*', so not a comment. This is an error. */
+<DEFINE>[/][^*]{NONSPACE}* {
+ BEGIN INITIAL;
+ glcpp_error(yylloc, yyextra, "#define followed by a non-identifier: %s", yytext);
+ RETURN_STRING_TOKEN (INTEGER_STRING);
+}
+
+ /* A character that can't start an identifier, comment, or
+ * space. This is an error. */
+<DEFINE>[^_a-zA-Z/[:space:]]{NONSPACE}* {
+ BEGIN INITIAL;
+ glcpp_error(yylloc, yyextra, "#define followed by a non-identifier: %s", yytext);
+ RETURN_STRING_TOKEN (INTEGER_STRING);
+}
+
+{DECIMAL_INTEGER} {
+ RETURN_STRING_TOKEN (INTEGER_STRING);
+}
+
+{OCTAL_INTEGER} {
+ RETURN_STRING_TOKEN (INTEGER_STRING);
+}
+
+{HEXADECIMAL_INTEGER} {
+ RETURN_STRING_TOKEN (INTEGER_STRING);
+}
+
+"<<" {
+ RETURN_TOKEN (LEFT_SHIFT);
+}
+
+">>" {
+ RETURN_TOKEN (RIGHT_SHIFT);
+}
+
+"<=" {
+ RETURN_TOKEN (LESS_OR_EQUAL);
+}
+
+">=" {
+ RETURN_TOKEN (GREATER_OR_EQUAL);
+}
+
+"==" {
+ RETURN_TOKEN (EQUAL);
+}
+
+"!=" {
+ RETURN_TOKEN (NOT_EQUAL);
+}
+
+"&&" {
+ RETURN_TOKEN (AND);
+}
+
+"||" {
+ RETURN_TOKEN (OR);
+}
+
+"++" {
+ RETURN_TOKEN (PLUS_PLUS);
+}
+
+"--" {
+ RETURN_TOKEN (MINUS_MINUS);
+}
+
+"##" {
+ if (! parser->skipping) {
+ if (parser->is_gles)
+ glcpp_error(yylloc, yyextra, "Token pasting (##) is illegal in GLES");
+ RETURN_TOKEN (PASTE);
+ }
+}
+
+"defined" {
+ RETURN_TOKEN (DEFINED);
+}
+
+{IDENTIFIER} {
+ RETURN_STRING_TOKEN (IDENTIFIER);
+}
+
+{PP_NUMBER} {
+ RETURN_STRING_TOKEN (OTHER);
+}
+
+{PUNCTUATION} {
+ RETURN_TOKEN (yytext[0]);
+}
+
+{OTHER}+ {
+ RETURN_STRING_TOKEN (OTHER);
+}
+
+{HSPACE} {
+ if (yyextra->space_tokens) {
+ RETURN_TOKEN (SPACE);
+ }
+}
+
+ /* We preserve all newlines, even between #if 0..#endif, so no
+ skipping.. */
+<*>{NEWLINE} {
+ if (parser->commented_newlines) {
+ BEGIN NEWLINE_CATCHUP;
+ } else {
+ BEGIN INITIAL;
+ }
+ yyextra->space_tokens = 1;
+ yyextra->lexing_directive = 0;
+ yylineno++;
+ yycolumn = 0;
+ RETURN_TOKEN_NEVER_SKIP (NEWLINE);
+}
+
+<INITIAL,COMMENT,DEFINE,HASH><<EOF>> {
+ if (YY_START == COMMENT)
+ glcpp_error(yylloc, yyextra, "Unterminated comment");
+ BEGIN DONE; /* Don't keep matching this rule forever. */
+ yyextra->lexing_directive = 0;
+ if (! parser->last_token_was_newline)
+ RETURN_TOKEN (NEWLINE);
+}
+
+ /* This is a catch-all to avoid the annoying default flex action which
+ * matches any character and prints it. If any input ever matches this
+ * rule, then we have made a mistake above and need to fix one or more
+ * of the preceding patterns to match that input. */
+
+<*>. {
+ glcpp_error(yylloc, yyextra, "Internal compiler error: Unexpected character: %s", yytext);
+
+ /* We don't actually use the UNREACHABLE start condition. We
+ only have this block here so that we can pretend to call some
+ generated functions, (to avoid "defined but not used"
+ warnings. */
+ if (YY_START == UNREACHABLE) {
+ unput('.');
+ yy_top_state(yyextra);
+ }
+}
+
+%%
+
+void
+glcpp_lex_set_source_string(glcpp_parser_t *parser, const char *shader)
+{
+ yy_scan_string(shader, parser->scanner);
+}
diff --git a/src/compiler/glsl/glcpp/glcpp-parse.y b/src/compiler/glsl/glcpp/glcpp-parse.y
new file mode 100644
index 00000000000..ef1a6575aaa
--- /dev/null
+++ b/src/compiler/glsl/glcpp/glcpp-parse.y
@@ -0,0 +1,2557 @@
+%{
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <inttypes.h>
+
+#include "glcpp.h"
+#include "main/core.h" /* for struct gl_extensions */
+#include "main/mtypes.h" /* for gl_api enum */
+
+static void
+yyerror (YYLTYPE *locp, glcpp_parser_t *parser, const char *error);
+
+static void
+_define_object_macro (glcpp_parser_t *parser,
+ YYLTYPE *loc,
+ const char *macro,
+ token_list_t *replacements);
+
+static void
+_define_function_macro (glcpp_parser_t *parser,
+ YYLTYPE *loc,
+ const char *macro,
+ string_list_t *parameters,
+ token_list_t *replacements);
+
+static string_list_t *
+_string_list_create (void *ctx);
+
+static void
+_string_list_append_item (string_list_t *list, const char *str);
+
+static int
+_string_list_contains (string_list_t *list, const char *member, int *index);
+
+static const char *
+_string_list_has_duplicate (string_list_t *list);
+
+static int
+_string_list_length (string_list_t *list);
+
+static int
+_string_list_equal (string_list_t *a, string_list_t *b);
+
+static argument_list_t *
+_argument_list_create (void *ctx);
+
+static void
+_argument_list_append (argument_list_t *list, token_list_t *argument);
+
+static int
+_argument_list_length (argument_list_t *list);
+
+static token_list_t *
+_argument_list_member_at (argument_list_t *list, int index);
+
+/* Note: This function ralloc_steal()s the str pointer. */
+static token_t *
+_token_create_str (void *ctx, int type, char *str);
+
+static token_t *
+_token_create_ival (void *ctx, int type, int ival);
+
+static token_list_t *
+_token_list_create (void *ctx);
+
+static void
+_token_list_append (token_list_t *list, token_t *token);
+
+static void
+_token_list_append_list (token_list_t *list, token_list_t *tail);
+
+static int
+_token_list_equal_ignoring_space (token_list_t *a, token_list_t *b);
+
+static void
+_parser_active_list_push (glcpp_parser_t *parser,
+ const char *identifier,
+ token_node_t *marker);
+
+static void
+_parser_active_list_pop (glcpp_parser_t *parser);
+
+static int
+_parser_active_list_contains (glcpp_parser_t *parser, const char *identifier);
+
+typedef enum {
+ EXPANSION_MODE_IGNORE_DEFINED,
+ EXPANSION_MODE_EVALUATE_DEFINED
+} expansion_mode_t;
+
+/* Expand list, and begin lexing from the result (after first
+ * prefixing a token of type 'head_token_type').
+ */
+static void
+_glcpp_parser_expand_and_lex_from (glcpp_parser_t *parser,
+ int head_token_type,
+ token_list_t *list,
+ expansion_mode_t mode);
+
+/* Perform macro expansion in-place on the given list. */
+static void
+_glcpp_parser_expand_token_list (glcpp_parser_t *parser,
+ token_list_t *list,
+ expansion_mode_t mode);
+
+static void
+_glcpp_parser_print_expanded_token_list (glcpp_parser_t *parser,
+ token_list_t *list);
+
+static void
+_glcpp_parser_skip_stack_push_if (glcpp_parser_t *parser, YYLTYPE *loc,
+ int condition);
+
+static void
+_glcpp_parser_skip_stack_change_if (glcpp_parser_t *parser, YYLTYPE *loc,
+ const char *type, int condition);
+
+static void
+_glcpp_parser_skip_stack_pop (glcpp_parser_t *parser, YYLTYPE *loc);
+
+static void
+_glcpp_parser_handle_version_declaration(glcpp_parser_t *parser, intmax_t version,
+ const char *ident, bool explicitly_set);
+
+static int
+glcpp_parser_lex (YYSTYPE *yylval, YYLTYPE *yylloc, glcpp_parser_t *parser);
+
+static void
+glcpp_parser_lex_from (glcpp_parser_t *parser, token_list_t *list);
+
+static void
+add_builtin_define(glcpp_parser_t *parser, const char *name, int value);
+
+%}
+
+%pure-parser
+%error-verbose
+
+%locations
+%initial-action {
+ @$.first_line = 1;
+ @$.first_column = 1;
+ @$.last_line = 1;
+ @$.last_column = 1;
+ @$.source = 0;
+}
+
+%parse-param {glcpp_parser_t *parser}
+%lex-param {glcpp_parser_t *parser}
+
+%expect 0
+
+ /* We use HASH_TOKEN, DEFINE_TOKEN and VERSION_TOKEN (as opposed to
+ * HASH, DEFINE, and VERSION) to avoid conflicts with other symbols,
+ * (such as the <HASH> and <DEFINE> start conditions in the lexer). */
+%token DEFINED ELIF_EXPANDED HASH_TOKEN DEFINE_TOKEN FUNC_IDENTIFIER OBJ_IDENTIFIER ELIF ELSE ENDIF ERROR_TOKEN IF IFDEF IFNDEF LINE PRAGMA UNDEF VERSION_TOKEN GARBAGE IDENTIFIER IF_EXPANDED INTEGER INTEGER_STRING LINE_EXPANDED NEWLINE OTHER PLACEHOLDER SPACE PLUS_PLUS MINUS_MINUS
+%token PASTE
+%type <ival> INTEGER operator SPACE integer_constant
+%type <expression_value> expression
+%type <str> IDENTIFIER FUNC_IDENTIFIER OBJ_IDENTIFIER INTEGER_STRING OTHER ERROR_TOKEN PRAGMA
+%type <string_list> identifier_list
+%type <token> preprocessing_token
+%type <token_list> pp_tokens replacement_list text_line
+%left OR
+%left AND
+%left '|'
+%left '^'
+%left '&'
+%left EQUAL NOT_EQUAL
+%left '<' '>' LESS_OR_EQUAL GREATER_OR_EQUAL
+%left LEFT_SHIFT RIGHT_SHIFT
+%left '+' '-'
+%left '*' '/' '%'
+%right UNARY
+
+%debug
+
+%%
+
+input:
+ /* empty */
+| input line
+;
+
+line:
+ control_line
+| SPACE control_line
+| text_line {
+ _glcpp_parser_print_expanded_token_list (parser, $1);
+ ralloc_asprintf_rewrite_tail (&parser->output, &parser->output_length, "\n");
+ ralloc_free ($1);
+ }
+| expanded_line
+;
+
+expanded_line:
+ IF_EXPANDED expression NEWLINE {
+ if (parser->is_gles && $2.undefined_macro)
+ glcpp_error(& @1, parser, "undefined macro %s in expression (illegal in GLES)", $2.undefined_macro);
+ _glcpp_parser_skip_stack_push_if (parser, & @1, $2.value);
+ }
+| ELIF_EXPANDED expression NEWLINE {
+ if (parser->is_gles && $2.undefined_macro)
+ glcpp_error(& @1, parser, "undefined macro %s in expression (illegal in GLES)", $2.undefined_macro);
+ _glcpp_parser_skip_stack_change_if (parser, & @1, "elif", $2.value);
+ }
+| LINE_EXPANDED integer_constant NEWLINE {
+ parser->has_new_line_number = 1;
+ parser->new_line_number = $2;
+ ralloc_asprintf_rewrite_tail (&parser->output,
+ &parser->output_length,
+ "#line %" PRIiMAX "\n",
+ $2);
+ }
+| LINE_EXPANDED integer_constant integer_constant NEWLINE {
+ parser->has_new_line_number = 1;
+ parser->new_line_number = $2;
+ parser->has_new_source_number = 1;
+ parser->new_source_number = $3;
+ ralloc_asprintf_rewrite_tail (&parser->output,
+ &parser->output_length,
+ "#line %" PRIiMAX " %" PRIiMAX "\n",
+ $2, $3);
+ }
+;
+
+define:
+ OBJ_IDENTIFIER replacement_list NEWLINE {
+ _define_object_macro (parser, & @1, $1, $2);
+ }
+| FUNC_IDENTIFIER '(' ')' replacement_list NEWLINE {
+ _define_function_macro (parser, & @1, $1, NULL, $4);
+ }
+| FUNC_IDENTIFIER '(' identifier_list ')' replacement_list NEWLINE {
+ _define_function_macro (parser, & @1, $1, $3, $5);
+ }
+;
+
+control_line:
+ control_line_success {
+ ralloc_asprintf_rewrite_tail (&parser->output, &parser->output_length, "\n");
+ }
+| control_line_error
+| HASH_TOKEN LINE {
+ glcpp_parser_resolve_implicit_version(parser);
+ } pp_tokens NEWLINE {
+
+ if (parser->skip_stack == NULL ||
+ parser->skip_stack->type == SKIP_NO_SKIP)
+ {
+ _glcpp_parser_expand_and_lex_from (parser,
+ LINE_EXPANDED, $4,
+ EXPANSION_MODE_IGNORE_DEFINED);
+ }
+ }
+;
+
+control_line_success:
+ HASH_TOKEN DEFINE_TOKEN {
+ glcpp_parser_resolve_implicit_version(parser);
+ } define
+| HASH_TOKEN UNDEF {
+ glcpp_parser_resolve_implicit_version(parser);
+ } IDENTIFIER NEWLINE {
+ macro_t *macro;
+ if (strcmp("__LINE__", $4) == 0
+ || strcmp("__FILE__", $4) == 0
+ || strcmp("__VERSION__", $4) == 0
+ || strncmp("GL_", $4, 3) == 0)
+ glcpp_error(& @1, parser, "Built-in (pre-defined)"
+ " macro names cannot be undefined.");
+
+ macro = hash_table_find (parser->defines, $4);
+ if (macro) {
+ hash_table_remove (parser->defines, $4);
+ ralloc_free (macro);
+ }
+ ralloc_free ($4);
+ }
+| HASH_TOKEN IF {
+ glcpp_parser_resolve_implicit_version(parser);
+ } pp_tokens NEWLINE {
+ /* Be careful to only evaluate the 'if' expression if
+ * we are not skipping. When we are skipping, we
+ * simply push a new 0-valued 'if' onto the skip
+ * stack.
+ *
+ * This avoids generating diagnostics for invalid
+ * expressions that are being skipped. */
+ if (parser->skip_stack == NULL ||
+ parser->skip_stack->type == SKIP_NO_SKIP)
+ {
+ _glcpp_parser_expand_and_lex_from (parser,
+ IF_EXPANDED, $4,
+ EXPANSION_MODE_EVALUATE_DEFINED);
+ }
+ else
+ {
+ _glcpp_parser_skip_stack_push_if (parser, & @1, 0);
+ parser->skip_stack->type = SKIP_TO_ENDIF;
+ }
+ }
+| HASH_TOKEN IF NEWLINE {
+ /* #if without an expression is only an error if we
+ * are not skipping */
+ if (parser->skip_stack == NULL ||
+ parser->skip_stack->type == SKIP_NO_SKIP)
+ {
+ glcpp_error(& @1, parser, "#if with no expression");
+ }
+ _glcpp_parser_skip_stack_push_if (parser, & @1, 0);
+ }
+| HASH_TOKEN IFDEF {
+ glcpp_parser_resolve_implicit_version(parser);
+ } IDENTIFIER junk NEWLINE {
+ macro_t *macro = hash_table_find (parser->defines, $4);
+ ralloc_free ($4);
+ _glcpp_parser_skip_stack_push_if (parser, & @1, macro != NULL);
+ }
+| HASH_TOKEN IFNDEF {
+ glcpp_parser_resolve_implicit_version(parser);
+ } IDENTIFIER junk NEWLINE {
+ macro_t *macro = hash_table_find (parser->defines, $4);
+ ralloc_free ($4);
+ _glcpp_parser_skip_stack_push_if (parser, & @3, macro == NULL);
+ }
+| HASH_TOKEN ELIF pp_tokens NEWLINE {
+ /* Be careful to only evaluate the 'elif' expression
+ * if we are not skipping. When we are skipping, we
+ * simply change to a 0-valued 'elif' on the skip
+ * stack.
+ *
+ * This avoids generating diagnostics for invalid
+ * expressions that are being skipped. */
+ if (parser->skip_stack &&
+ parser->skip_stack->type == SKIP_TO_ELSE)
+ {
+ _glcpp_parser_expand_and_lex_from (parser,
+ ELIF_EXPANDED, $3,
+ EXPANSION_MODE_EVALUATE_DEFINED);
+ }
+ else if (parser->skip_stack &&
+ parser->skip_stack->has_else)
+ {
+ glcpp_error(& @1, parser, "#elif after #else");
+ }
+ else
+ {
+ _glcpp_parser_skip_stack_change_if (parser, & @1,
+ "elif", 0);
+ }
+ }
+| HASH_TOKEN ELIF NEWLINE {
+ /* #elif without an expression is an error unless we
+ * are skipping. */
+ if (parser->skip_stack &&
+ parser->skip_stack->type == SKIP_TO_ELSE)
+ {
+ glcpp_error(& @1, parser, "#elif with no expression");
+ }
+ else if (parser->skip_stack &&
+ parser->skip_stack->has_else)
+ {
+ glcpp_error(& @1, parser, "#elif after #else");
+ }
+ else
+ {
+ _glcpp_parser_skip_stack_change_if (parser, & @1,
+ "elif", 0);
+ glcpp_warning(& @1, parser, "ignoring illegal #elif without expression");
+ }
+ }
+| HASH_TOKEN ELSE { parser->lexing_directive = 1; } NEWLINE {
+ if (parser->skip_stack &&
+ parser->skip_stack->has_else)
+ {
+ glcpp_error(& @1, parser, "multiple #else");
+ }
+ else
+ {
+ _glcpp_parser_skip_stack_change_if (parser, & @1, "else", 1);
+ if (parser->skip_stack)
+ parser->skip_stack->has_else = true;
+ }
+ }
+| HASH_TOKEN ENDIF {
+ _glcpp_parser_skip_stack_pop (parser, & @1);
+ } NEWLINE
+| HASH_TOKEN VERSION_TOKEN integer_constant NEWLINE {
+ if (parser->version_resolved) {
+ glcpp_error(& @1, parser, "#version must appear on the first line");
+ }
+ _glcpp_parser_handle_version_declaration(parser, $3, NULL, true);
+ }
+| HASH_TOKEN VERSION_TOKEN integer_constant IDENTIFIER NEWLINE {
+ if (parser->version_resolved) {
+ glcpp_error(& @1, parser, "#version must appear on the first line");
+ }
+ _glcpp_parser_handle_version_declaration(parser, $3, $4, true);
+ }
+| HASH_TOKEN NEWLINE {
+ glcpp_parser_resolve_implicit_version(parser);
+ }
+| HASH_TOKEN PRAGMA NEWLINE {
+ ralloc_asprintf_rewrite_tail (&parser->output, &parser->output_length, "#%s", $2);
+ }
+;
+
+control_line_error:
+ HASH_TOKEN ERROR_TOKEN NEWLINE {
+ glcpp_error(& @1, parser, "#%s", $2);
+ }
+| HASH_TOKEN DEFINE_TOKEN NEWLINE {
+ glcpp_error (& @1, parser, "#define without macro name");
+ }
+| HASH_TOKEN GARBAGE pp_tokens NEWLINE {
+ glcpp_error (& @1, parser, "Illegal non-directive after #");
+ }
+;
+
+integer_constant:
+ INTEGER_STRING {
+ if (strlen ($1) >= 3 && strncmp ($1, "0x", 2) == 0) {
+ $$ = strtoll ($1 + 2, NULL, 16);
+ } else if ($1[0] == '0') {
+ $$ = strtoll ($1, NULL, 8);
+ } else {
+ $$ = strtoll ($1, NULL, 10);
+ }
+ }
+| INTEGER {
+ $$ = $1;
+ }
+
+expression:
+ integer_constant {
+ $$.value = $1;
+ $$.undefined_macro = NULL;
+ }
+| IDENTIFIER {
+ $$.value = 0;
+ if (parser->is_gles)
+ $$.undefined_macro = ralloc_strdup (parser, $1);
+ else
+ $$.undefined_macro = NULL;
+ }
+| expression OR expression {
+ $$.value = $1.value || $3.value;
+
+ /* Short-circuit: Only flag undefined from right side
+ * if left side evaluates to false.
+ */
+ if ($1.undefined_macro)
+ $$.undefined_macro = $1.undefined_macro;
+ else if (! $1.value)
+ $$.undefined_macro = $3.undefined_macro;
+ }
+| expression AND expression {
+ $$.value = $1.value && $3.value;
+
+ /* Short-circuit: Only flag undefined from right-side
+ * if left side evaluates to true.
+ */
+ if ($1.undefined_macro)
+ $$.undefined_macro = $1.undefined_macro;
+ else if ($1.value)
+ $$.undefined_macro = $3.undefined_macro;
+ }
+| expression '|' expression {
+ $$.value = $1.value | $3.value;
+ if ($1.undefined_macro)
+ $$.undefined_macro = $1.undefined_macro;
+ else
+ $$.undefined_macro = $3.undefined_macro;
+ }
+| expression '^' expression {
+ $$.value = $1.value ^ $3.value;
+ if ($1.undefined_macro)
+ $$.undefined_macro = $1.undefined_macro;
+ else
+ $$.undefined_macro = $3.undefined_macro;
+ }
+| expression '&' expression {
+ $$.value = $1.value & $3.value;
+ if ($1.undefined_macro)
+ $$.undefined_macro = $1.undefined_macro;
+ else
+ $$.undefined_macro = $3.undefined_macro;
+ }
+| expression NOT_EQUAL expression {
+ $$.value = $1.value != $3.value;
+ if ($1.undefined_macro)
+ $$.undefined_macro = $1.undefined_macro;
+ else
+ $$.undefined_macro = $3.undefined_macro;
+ }
+| expression EQUAL expression {
+ $$.value = $1.value == $3.value;
+ if ($1.undefined_macro)
+ $$.undefined_macro = $1.undefined_macro;
+ else
+ $$.undefined_macro = $3.undefined_macro;
+ }
+| expression GREATER_OR_EQUAL expression {
+ $$.value = $1.value >= $3.value;
+ if ($1.undefined_macro)
+ $$.undefined_macro = $1.undefined_macro;
+ else
+ $$.undefined_macro = $3.undefined_macro;
+ }
+| expression LESS_OR_EQUAL expression {
+ $$.value = $1.value <= $3.value;
+ if ($1.undefined_macro)
+ $$.undefined_macro = $1.undefined_macro;
+ else
+ $$.undefined_macro = $3.undefined_macro;
+ }
+| expression '>' expression {
+ $$.value = $1.value > $3.value;
+ if ($1.undefined_macro)
+ $$.undefined_macro = $1.undefined_macro;
+ else
+ $$.undefined_macro = $3.undefined_macro;
+ }
+| expression '<' expression {
+ $$.value = $1.value < $3.value;
+ if ($1.undefined_macro)
+ $$.undefined_macro = $1.undefined_macro;
+ else
+ $$.undefined_macro = $3.undefined_macro;
+ }
+| expression RIGHT_SHIFT expression {
+ $$.value = $1.value >> $3.value;
+ if ($1.undefined_macro)
+ $$.undefined_macro = $1.undefined_macro;
+ else
+ $$.undefined_macro = $3.undefined_macro;
+ }
+| expression LEFT_SHIFT expression {
+ $$.value = $1.value << $3.value;
+ if ($1.undefined_macro)
+ $$.undefined_macro = $1.undefined_macro;
+ else
+ $$.undefined_macro = $3.undefined_macro;
+ }
+| expression '-' expression {
+ $$.value = $1.value - $3.value;
+ if ($1.undefined_macro)
+ $$.undefined_macro = $1.undefined_macro;
+ else
+ $$.undefined_macro = $3.undefined_macro;
+ }
+| expression '+' expression {
+ $$.value = $1.value + $3.value;
+ if ($1.undefined_macro)
+ $$.undefined_macro = $1.undefined_macro;
+ else
+ $$.undefined_macro = $3.undefined_macro;
+ }
+| expression '%' expression {
+ if ($3.value == 0) {
+ yyerror (& @1, parser,
+ "zero modulus in preprocessor directive");
+ } else {
+ $$.value = $1.value % $3.value;
+ }
+ if ($1.undefined_macro)
+ $$.undefined_macro = $1.undefined_macro;
+ else
+ $$.undefined_macro = $3.undefined_macro;
+ }
+| expression '/' expression {
+ if ($3.value == 0) {
+ yyerror (& @1, parser,
+ "division by 0 in preprocessor directive");
+ } else {
+ $$.value = $1.value / $3.value;
+ }
+ if ($1.undefined_macro)
+ $$.undefined_macro = $1.undefined_macro;
+ else
+ $$.undefined_macro = $3.undefined_macro;
+ }
+| expression '*' expression {
+ $$.value = $1.value * $3.value;
+ if ($1.undefined_macro)
+ $$.undefined_macro = $1.undefined_macro;
+ else
+ $$.undefined_macro = $3.undefined_macro;
+ }
+| '!' expression %prec UNARY {
+ $$.value = ! $2.value;
+ $$.undefined_macro = $2.undefined_macro;
+ }
+| '~' expression %prec UNARY {
+ $$.value = ~ $2.value;
+ $$.undefined_macro = $2.undefined_macro;
+ }
+| '-' expression %prec UNARY {
+ $$.value = - $2.value;
+ $$.undefined_macro = $2.undefined_macro;
+ }
+| '+' expression %prec UNARY {
+ $$.value = + $2.value;
+ $$.undefined_macro = $2.undefined_macro;
+ }
+| '(' expression ')' {
+ $$ = $2;
+ }
+;
+
+identifier_list:
+ IDENTIFIER {
+ $$ = _string_list_create (parser);
+ _string_list_append_item ($$, $1);
+ ralloc_steal ($$, $1);
+ }
+| identifier_list ',' IDENTIFIER {
+ $$ = $1;
+ _string_list_append_item ($$, $3);
+ ralloc_steal ($$, $3);
+ }
+;
+
+text_line:
+ NEWLINE { $$ = NULL; }
+| pp_tokens NEWLINE
+;
+
+replacement_list:
+ /* empty */ { $$ = NULL; }
+| pp_tokens
+;
+
+junk:
+ /* empty */
+| pp_tokens {
+ glcpp_error(&@1, parser, "extra tokens at end of directive");
+ }
+;
+
+pp_tokens:
+ preprocessing_token {
+ parser->space_tokens = 1;
+ $$ = _token_list_create (parser);
+ _token_list_append ($$, $1);
+ }
+| pp_tokens preprocessing_token {
+ $$ = $1;
+ _token_list_append ($$, $2);
+ }
+;
+
+preprocessing_token:
+ IDENTIFIER {
+ $$ = _token_create_str (parser, IDENTIFIER, $1);
+ $$->location = yylloc;
+ }
+| INTEGER_STRING {
+ $$ = _token_create_str (parser, INTEGER_STRING, $1);
+ $$->location = yylloc;
+ }
+| operator {
+ $$ = _token_create_ival (parser, $1, $1);
+ $$->location = yylloc;
+ }
+| DEFINED {
+ $$ = _token_create_ival (parser, DEFINED, DEFINED);
+ $$->location = yylloc;
+ }
+| OTHER {
+ $$ = _token_create_str (parser, OTHER, $1);
+ $$->location = yylloc;
+ }
+| SPACE {
+ $$ = _token_create_ival (parser, SPACE, SPACE);
+ $$->location = yylloc;
+ }
+;
+
+operator:
+ '[' { $$ = '['; }
+| ']' { $$ = ']'; }
+| '(' { $$ = '('; }
+| ')' { $$ = ')'; }
+| '{' { $$ = '{'; }
+| '}' { $$ = '}'; }
+| '.' { $$ = '.'; }
+| '&' { $$ = '&'; }
+| '*' { $$ = '*'; }
+| '+' { $$ = '+'; }
+| '-' { $$ = '-'; }
+| '~' { $$ = '~'; }
+| '!' { $$ = '!'; }
+| '/' { $$ = '/'; }
+| '%' { $$ = '%'; }
+| LEFT_SHIFT { $$ = LEFT_SHIFT; }
+| RIGHT_SHIFT { $$ = RIGHT_SHIFT; }
+| '<' { $$ = '<'; }
+| '>' { $$ = '>'; }
+| LESS_OR_EQUAL { $$ = LESS_OR_EQUAL; }
+| GREATER_OR_EQUAL { $$ = GREATER_OR_EQUAL; }
+| EQUAL { $$ = EQUAL; }
+| NOT_EQUAL { $$ = NOT_EQUAL; }
+| '^' { $$ = '^'; }
+| '|' { $$ = '|'; }
+| AND { $$ = AND; }
+| OR { $$ = OR; }
+| ';' { $$ = ';'; }
+| ',' { $$ = ','; }
+| '=' { $$ = '='; }
+| PASTE { $$ = PASTE; }
+| PLUS_PLUS { $$ = PLUS_PLUS; }
+| MINUS_MINUS { $$ = MINUS_MINUS; }
+;
+
+%%
+
+string_list_t *
+_string_list_create (void *ctx)
+{
+ string_list_t *list;
+
+ list = ralloc (ctx, string_list_t);
+ list->head = NULL;
+ list->tail = NULL;
+
+ return list;
+}
+
+void
+_string_list_append_item (string_list_t *list, const char *str)
+{
+ string_node_t *node;
+
+ node = ralloc (list, string_node_t);
+ node->str = ralloc_strdup (node, str);
+
+ node->next = NULL;
+
+ if (list->head == NULL) {
+ list->head = node;
+ } else {
+ list->tail->next = node;
+ }
+
+ list->tail = node;
+}
+
+int
+_string_list_contains (string_list_t *list, const char *member, int *index)
+{
+ string_node_t *node;
+ int i;
+
+ if (list == NULL)
+ return 0;
+
+ for (i = 0, node = list->head; node; i++, node = node->next) {
+ if (strcmp (node->str, member) == 0) {
+ if (index)
+ *index = i;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Return duplicate string in list (if any), NULL otherwise. */
+const char *
+_string_list_has_duplicate (string_list_t *list)
+{
+ string_node_t *node, *dup;
+
+ if (list == NULL)
+ return NULL;
+
+ for (node = list->head; node; node = node->next) {
+ for (dup = node->next; dup; dup = dup->next) {
+ if (strcmp (node->str, dup->str) == 0)
+ return node->str;
+ }
+ }
+
+ return NULL;
+}
+
+int
+_string_list_length (string_list_t *list)
+{
+ int length = 0;
+ string_node_t *node;
+
+ if (list == NULL)
+ return 0;
+
+ for (node = list->head; node; node = node->next)
+ length++;
+
+ return length;
+}
+
+int
+_string_list_equal (string_list_t *a, string_list_t *b)
+{
+ string_node_t *node_a, *node_b;
+
+ if (a == NULL && b == NULL)
+ return 1;
+
+ if (a == NULL || b == NULL)
+ return 0;
+
+ for (node_a = a->head, node_b = b->head;
+ node_a && node_b;
+ node_a = node_a->next, node_b = node_b->next)
+ {
+ if (strcmp (node_a->str, node_b->str))
+ return 0;
+ }
+
+ /* Catch the case of lists being different lengths, (which
+ * would cause the loop above to terminate after the shorter
+ * list). */
+ return node_a == node_b;
+}
+
+argument_list_t *
+_argument_list_create (void *ctx)
+{
+ argument_list_t *list;
+
+ list = ralloc (ctx, argument_list_t);
+ list->head = NULL;
+ list->tail = NULL;
+
+ return list;
+}
+
+void
+_argument_list_append (argument_list_t *list, token_list_t *argument)
+{
+ argument_node_t *node;
+
+ node = ralloc (list, argument_node_t);
+ node->argument = argument;
+
+ node->next = NULL;
+
+ if (list->head == NULL) {
+ list->head = node;
+ } else {
+ list->tail->next = node;
+ }
+
+ list->tail = node;
+}
+
+int
+_argument_list_length (argument_list_t *list)
+{
+ int length = 0;
+ argument_node_t *node;
+
+ if (list == NULL)
+ return 0;
+
+ for (node = list->head; node; node = node->next)
+ length++;
+
+ return length;
+}
+
+token_list_t *
+_argument_list_member_at (argument_list_t *list, int index)
+{
+ argument_node_t *node;
+ int i;
+
+ if (list == NULL)
+ return NULL;
+
+ node = list->head;
+ for (i = 0; i < index; i++) {
+ node = node->next;
+ if (node == NULL)
+ break;
+ }
+
+ if (node)
+ return node->argument;
+
+ return NULL;
+}
+
+/* Note: This function ralloc_steal()s the str pointer. */
+token_t *
+_token_create_str (void *ctx, int type, char *str)
+{
+ token_t *token;
+
+ token = ralloc (ctx, token_t);
+ token->type = type;
+ token->value.str = str;
+
+ ralloc_steal (token, str);
+
+ return token;
+}
+
+token_t *
+_token_create_ival (void *ctx, int type, int ival)
+{
+ token_t *token;
+
+ token = ralloc (ctx, token_t);
+ token->type = type;
+ token->value.ival = ival;
+
+ return token;
+}
+
+token_list_t *
+_token_list_create (void *ctx)
+{
+ token_list_t *list;
+
+ list = ralloc (ctx, token_list_t);
+ list->head = NULL;
+ list->tail = NULL;
+ list->non_space_tail = NULL;
+
+ return list;
+}
+
+void
+_token_list_append (token_list_t *list, token_t *token)
+{
+ token_node_t *node;
+
+ node = ralloc (list, token_node_t);
+ node->token = token;
+ node->next = NULL;
+
+ if (list->head == NULL) {
+ list->head = node;
+ } else {
+ list->tail->next = node;
+ }
+
+ list->tail = node;
+ if (token->type != SPACE)
+ list->non_space_tail = node;
+}
+
+void
+_token_list_append_list (token_list_t *list, token_list_t *tail)
+{
+ if (tail == NULL || tail->head == NULL)
+ return;
+
+ if (list->head == NULL) {
+ list->head = tail->head;
+ } else {
+ list->tail->next = tail->head;
+ }
+
+ list->tail = tail->tail;
+ list->non_space_tail = tail->non_space_tail;
+}
+
+static token_list_t *
+_token_list_copy (void *ctx, token_list_t *other)
+{
+ token_list_t *copy;
+ token_node_t *node;
+
+ if (other == NULL)
+ return NULL;
+
+ copy = _token_list_create (ctx);
+ for (node = other->head; node; node = node->next) {
+ token_t *new_token = ralloc (copy, token_t);
+ *new_token = *node->token;
+ _token_list_append (copy, new_token);
+ }
+
+ return copy;
+}
+
+static void
+_token_list_trim_trailing_space (token_list_t *list)
+{
+ token_node_t *tail, *next;
+
+ if (list->non_space_tail) {
+ tail = list->non_space_tail->next;
+ list->non_space_tail->next = NULL;
+ list->tail = list->non_space_tail;
+
+ while (tail) {
+ next = tail->next;
+ ralloc_free (tail);
+ tail = next;
+ }
+ }
+}
+
+static int
+_token_list_is_empty_ignoring_space (token_list_t *l)
+{
+ token_node_t *n;
+
+ if (l == NULL)
+ return 1;
+
+ n = l->head;
+ while (n != NULL && n->token->type == SPACE)
+ n = n->next;
+
+ return n == NULL;
+}
+
+int
+_token_list_equal_ignoring_space (token_list_t *a, token_list_t *b)
+{
+ token_node_t *node_a, *node_b;
+
+ if (a == NULL || b == NULL) {
+ int a_empty = _token_list_is_empty_ignoring_space(a);
+ int b_empty = _token_list_is_empty_ignoring_space(b);
+ return a_empty == b_empty;
+ }
+
+ node_a = a->head;
+ node_b = b->head;
+
+ while (1)
+ {
+ if (node_a == NULL && node_b == NULL)
+ break;
+
+ if (node_a == NULL || node_b == NULL)
+ return 0;
+ /* Make sure whitespace appears in the same places in both.
+ * It need not be exactly the same amount of whitespace,
+ * though.
+ */
+ if (node_a->token->type == SPACE
+ && node_b->token->type == SPACE) {
+ while (node_a && node_a->token->type == SPACE)
+ node_a = node_a->next;
+ while (node_b && node_b->token->type == SPACE)
+ node_b = node_b->next;
+ continue;
+ }
+
+ if (node_a->token->type != node_b->token->type)
+ return 0;
+
+ switch (node_a->token->type) {
+ case INTEGER:
+ if (node_a->token->value.ival !=
+ node_b->token->value.ival)
+ {
+ return 0;
+ }
+ break;
+ case IDENTIFIER:
+ case INTEGER_STRING:
+ case OTHER:
+ if (strcmp (node_a->token->value.str,
+ node_b->token->value.str))
+ {
+ return 0;
+ }
+ break;
+ }
+
+ node_a = node_a->next;
+ node_b = node_b->next;
+ }
+
+ return 1;
+}
+
+static void
+_token_print (char **out, size_t *len, token_t *token)
+{
+ if (token->type < 256) {
+ ralloc_asprintf_rewrite_tail (out, len, "%c", token->type);
+ return;
+ }
+
+ switch (token->type) {
+ case INTEGER:
+ ralloc_asprintf_rewrite_tail (out, len, "%" PRIiMAX, token->value.ival);
+ break;
+ case IDENTIFIER:
+ case INTEGER_STRING:
+ case OTHER:
+ ralloc_asprintf_rewrite_tail (out, len, "%s", token->value.str);
+ break;
+ case SPACE:
+ ralloc_asprintf_rewrite_tail (out, len, " ");
+ break;
+ case LEFT_SHIFT:
+ ralloc_asprintf_rewrite_tail (out, len, "<<");
+ break;
+ case RIGHT_SHIFT:
+ ralloc_asprintf_rewrite_tail (out, len, ">>");
+ break;
+ case LESS_OR_EQUAL:
+ ralloc_asprintf_rewrite_tail (out, len, "<=");
+ break;
+ case GREATER_OR_EQUAL:
+ ralloc_asprintf_rewrite_tail (out, len, ">=");
+ break;
+ case EQUAL:
+ ralloc_asprintf_rewrite_tail (out, len, "==");
+ break;
+ case NOT_EQUAL:
+ ralloc_asprintf_rewrite_tail (out, len, "!=");
+ break;
+ case AND:
+ ralloc_asprintf_rewrite_tail (out, len, "&&");
+ break;
+ case OR:
+ ralloc_asprintf_rewrite_tail (out, len, "||");
+ break;
+ case PASTE:
+ ralloc_asprintf_rewrite_tail (out, len, "##");
+ break;
+ case PLUS_PLUS:
+ ralloc_asprintf_rewrite_tail (out, len, "++");
+ break;
+ case MINUS_MINUS:
+ ralloc_asprintf_rewrite_tail (out, len, "--");
+ break;
+ case DEFINED:
+ ralloc_asprintf_rewrite_tail (out, len, "defined");
+ break;
+ case PLACEHOLDER:
+ /* Nothing to print. */
+ break;
+ default:
+ assert(!"Error: Don't know how to print token.");
+
+ break;
+ }
+}
+
+/* Return a new token (ralloc()ed off of 'token') formed by pasting
+ * 'token' and 'other'. Note that this function may return 'token' or
+ * 'other' directly rather than allocating anything new.
+ *
+ * Caution: Only very cursory error-checking is performed to see if
+ * the final result is a valid single token. */
+static token_t *
+_token_paste (glcpp_parser_t *parser, token_t *token, token_t *other)
+{
+ token_t *combined = NULL;
+
+ /* Pasting a placeholder onto anything makes no change. */
+ if (other->type == PLACEHOLDER)
+ return token;
+
+ /* When 'token' is a placeholder, just return 'other'. */
+ if (token->type == PLACEHOLDER)
+ return other;
+
+ /* A very few single-character punctuators can be combined
+ * with another to form a multi-character punctuator. */
+ switch (token->type) {
+ case '<':
+ if (other->type == '<')
+ combined = _token_create_ival (token, LEFT_SHIFT, LEFT_SHIFT);
+ else if (other->type == '=')
+ combined = _token_create_ival (token, LESS_OR_EQUAL, LESS_OR_EQUAL);
+ break;
+ case '>':
+ if (other->type == '>')
+ combined = _token_create_ival (token, RIGHT_SHIFT, RIGHT_SHIFT);
+ else if (other->type == '=')
+ combined = _token_create_ival (token, GREATER_OR_EQUAL, GREATER_OR_EQUAL);
+ break;
+ case '=':
+ if (other->type == '=')
+ combined = _token_create_ival (token, EQUAL, EQUAL);
+ break;
+ case '!':
+ if (other->type == '=')
+ combined = _token_create_ival (token, NOT_EQUAL, NOT_EQUAL);
+ break;
+ case '&':
+ if (other->type == '&')
+ combined = _token_create_ival (token, AND, AND);
+ break;
+ case '|':
+ if (other->type == '|')
+ combined = _token_create_ival (token, OR, OR);
+ break;
+ }
+
+ if (combined != NULL) {
+ /* Inherit the location from the first token */
+ combined->location = token->location;
+ return combined;
+ }
+
+ /* Two string-valued (or integer) tokens can usually just be
+ * mashed together. (We also handle a string followed by an
+ * integer here as well.)
+ *
+ * There are some exceptions here. Notably, if the first token
+ * is an integer (or a string representing an integer), then
+ * the second token must also be an integer or must be a
+ * string representing an integer that begins with a digit.
+ */
+ if ((token->type == IDENTIFIER || token->type == OTHER || token->type == INTEGER_STRING || token->type == INTEGER) &&
+ (other->type == IDENTIFIER || other->type == OTHER || other->type == INTEGER_STRING || other->type == INTEGER))
+ {
+ char *str;
+ int combined_type;
+
+ /* Check that pasting onto an integer doesn't create a
+ * non-integer, (that is, only digits can be
+ * pasted. */
+ if (token->type == INTEGER_STRING || token->type == INTEGER)
+ {
+ switch (other->type) {
+ case INTEGER_STRING:
+ if (other->value.str[0] < '0' ||
+ other->value.str[0] > '9')
+ goto FAIL;
+ break;
+ case INTEGER:
+ if (other->value.ival < 0)
+ goto FAIL;
+ break;
+ default:
+ goto FAIL;
+ }
+ }
+
+ if (token->type == INTEGER)
+ str = ralloc_asprintf (token, "%" PRIiMAX,
+ token->value.ival);
+ else
+ str = ralloc_strdup (token, token->value.str);
+
+
+ if (other->type == INTEGER)
+ ralloc_asprintf_append (&str, "%" PRIiMAX,
+ other->value.ival);
+ else
+ ralloc_strcat (&str, other->value.str);
+
+ /* New token is same type as original token, unless we
+ * started with an integer, in which case we will be
+ * creating an integer-string. */
+ combined_type = token->type;
+ if (combined_type == INTEGER)
+ combined_type = INTEGER_STRING;
+
+ combined = _token_create_str (token, combined_type, str);
+ combined->location = token->location;
+ return combined;
+ }
+
+ FAIL:
+ glcpp_error (&token->location, parser, "");
+ ralloc_asprintf_rewrite_tail (&parser->info_log, &parser->info_log_length, "Pasting \"");
+ _token_print (&parser->info_log, &parser->info_log_length, token);
+ ralloc_asprintf_rewrite_tail (&parser->info_log, &parser->info_log_length, "\" and \"");
+ _token_print (&parser->info_log, &parser->info_log_length, other);
+ ralloc_asprintf_rewrite_tail (&parser->info_log, &parser->info_log_length, "\" does not give a valid preprocessing token.\n");
+
+ return token;
+}
+
+static void
+_token_list_print (glcpp_parser_t *parser, token_list_t *list)
+{
+ token_node_t *node;
+
+ if (list == NULL)
+ return;
+
+ for (node = list->head; node; node = node->next)
+ _token_print (&parser->output, &parser->output_length, node->token);
+}
+
+void
+yyerror (YYLTYPE *locp, glcpp_parser_t *parser, const char *error)
+{
+ glcpp_error(locp, parser, "%s", error);
+}
+
+static void add_builtin_define(glcpp_parser_t *parser,
+ const char *name, int value)
+{
+ token_t *tok;
+ token_list_t *list;
+
+ tok = _token_create_ival (parser, INTEGER, value);
+
+ list = _token_list_create(parser);
+ _token_list_append(list, tok);
+ _define_object_macro(parser, NULL, name, list);
+}
+
+glcpp_parser_t *
+glcpp_parser_create (const struct gl_extensions *extensions, gl_api api)
+{
+ glcpp_parser_t *parser;
+
+ parser = ralloc (NULL, glcpp_parser_t);
+
+ glcpp_lex_init_extra (parser, &parser->scanner);
+ parser->defines = hash_table_ctor (32, hash_table_string_hash,
+ hash_table_string_compare);
+ parser->active = NULL;
+ parser->lexing_directive = 0;
+ parser->space_tokens = 1;
+ parser->last_token_was_newline = 0;
+ parser->last_token_was_space = 0;
+ parser->first_non_space_token_this_line = 1;
+ parser->newline_as_space = 0;
+ parser->in_control_line = 0;
+ parser->paren_count = 0;
+ parser->commented_newlines = 0;
+
+ parser->skip_stack = NULL;
+ parser->skipping = 0;
+
+ parser->lex_from_list = NULL;
+ parser->lex_from_node = NULL;
+
+ parser->output = ralloc_strdup(parser, "");
+ parser->output_length = 0;
+ parser->info_log = ralloc_strdup(parser, "");
+ parser->info_log_length = 0;
+ parser->error = 0;
+
+ parser->extensions = extensions;
+ parser->api = api;
+ parser->version_resolved = false;
+
+ parser->has_new_line_number = 0;
+ parser->new_line_number = 1;
+ parser->has_new_source_number = 0;
+ parser->new_source_number = 0;
+
+ return parser;
+}
+
+void
+glcpp_parser_destroy (glcpp_parser_t *parser)
+{
+ glcpp_lex_destroy (parser->scanner);
+ hash_table_dtor (parser->defines);
+ ralloc_free (parser);
+}
+
+typedef enum function_status
+{
+ FUNCTION_STATUS_SUCCESS,
+ FUNCTION_NOT_A_FUNCTION,
+ FUNCTION_UNBALANCED_PARENTHESES
+} function_status_t;
+
+/* Find a set of function-like macro arguments by looking for a
+ * balanced set of parentheses.
+ *
+ * When called, 'node' should be the opening-parenthesis token, (or
+ * perhaps preceeding SPACE tokens). Upon successful return *last will
+ * be the last consumed node, (corresponding to the closing right
+ * parenthesis).
+ *
+ * Return values:
+ *
+ * FUNCTION_STATUS_SUCCESS:
+ *
+ * Successfully parsed a set of function arguments.
+ *
+ * FUNCTION_NOT_A_FUNCTION:
+ *
+ * Macro name not followed by a '('. This is not an error, but
+ * simply that the macro name should be treated as a non-macro.
+ *
+ * FUNCTION_UNBALANCED_PARENTHESES
+ *
+ * Macro name is not followed by a balanced set of parentheses.
+ */
+static function_status_t
+_arguments_parse (argument_list_t *arguments,
+ token_node_t *node,
+ token_node_t **last)
+{
+ token_list_t *argument;
+ int paren_count;
+
+ node = node->next;
+
+ /* Ignore whitespace before first parenthesis. */
+ while (node && node->token->type == SPACE)
+ node = node->next;
+
+ if (node == NULL || node->token->type != '(')
+ return FUNCTION_NOT_A_FUNCTION;
+
+ node = node->next;
+
+ argument = _token_list_create (arguments);
+ _argument_list_append (arguments, argument);
+
+ for (paren_count = 1; node; node = node->next) {
+ if (node->token->type == '(')
+ {
+ paren_count++;
+ }
+ else if (node->token->type == ')')
+ {
+ paren_count--;
+ if (paren_count == 0)
+ break;
+ }
+
+ if (node->token->type == ',' &&
+ paren_count == 1)
+ {
+ _token_list_trim_trailing_space (argument);
+ argument = _token_list_create (arguments);
+ _argument_list_append (arguments, argument);
+ }
+ else {
+ if (argument->head == NULL) {
+ /* Don't treat initial whitespace as
+ * part of the argument. */
+ if (node->token->type == SPACE)
+ continue;
+ }
+ _token_list_append (argument, node->token);
+ }
+ }
+
+ if (paren_count)
+ return FUNCTION_UNBALANCED_PARENTHESES;
+
+ *last = node;
+
+ return FUNCTION_STATUS_SUCCESS;
+}
+
+static token_list_t *
+_token_list_create_with_one_ival (void *ctx, int type, int ival)
+{
+ token_list_t *list;
+ token_t *node;
+
+ list = _token_list_create (ctx);
+ node = _token_create_ival (list, type, ival);
+ _token_list_append (list, node);
+
+ return list;
+}
+
+static token_list_t *
+_token_list_create_with_one_space (void *ctx)
+{
+ return _token_list_create_with_one_ival (ctx, SPACE, SPACE);
+}
+
+static token_list_t *
+_token_list_create_with_one_integer (void *ctx, int ival)
+{
+ return _token_list_create_with_one_ival (ctx, INTEGER, ival);
+}
+
+/* Evaluate a DEFINED token node (based on subsequent tokens in the list).
+ *
+ * Note: This function must only be called when "node" is a DEFINED token,
+ * (and will abort with an assertion failure otherwise).
+ *
+ * If "node" is followed, (ignoring any SPACE tokens), by an IDENTIFIER token
+ * (optionally preceded and followed by '(' and ')' tokens) then the following
+ * occurs:
+ *
+ * If the identifier is a defined macro, this function returns 1.
+ *
+ * If the identifier is not a defined macro, this function returns 0.
+ *
+ * In either case, *last will be updated to the last node in the list
+ * consumed by the evaluation, (either the token of the identifier or the
+ * token of the closing parenthesis).
+ *
+ * In all other cases, (such as "node is the final node of the list", or
+ * "missing closing parenthesis", etc.), this function generates a
+ * preprocessor error, returns -1 and *last will not be set.
+ */
+static int
+_glcpp_parser_evaluate_defined (glcpp_parser_t *parser,
+ token_node_t *node,
+ token_node_t **last)
+{
+ token_node_t *argument, *defined = node;
+
+ assert (node->token->type == DEFINED);
+
+ node = node->next;
+
+ /* Ignore whitespace after DEFINED token. */
+ while (node && node->token->type == SPACE)
+ node = node->next;
+
+ if (node == NULL)
+ goto FAIL;
+
+ if (node->token->type == IDENTIFIER || node->token->type == OTHER) {
+ argument = node;
+ } else if (node->token->type == '(') {
+ node = node->next;
+
+ /* Ignore whitespace after '(' token. */
+ while (node && node->token->type == SPACE)
+ node = node->next;
+
+ if (node == NULL || (node->token->type != IDENTIFIER &&
+ node->token->type != OTHER))
+ {
+ goto FAIL;
+ }
+
+ argument = node;
+
+ node = node->next;
+
+ /* Ignore whitespace after identifier, before ')' token. */
+ while (node && node->token->type == SPACE)
+ node = node->next;
+
+ if (node == NULL || node->token->type != ')')
+ goto FAIL;
+ } else {
+ goto FAIL;
+ }
+
+ *last = node;
+
+ return hash_table_find (parser->defines,
+ argument->token->value.str) ? 1 : 0;
+
+FAIL:
+ glcpp_error (&defined->token->location, parser,
+ "\"defined\" not followed by an identifier");
+ return -1;
+}
+
+/* Evaluate all DEFINED nodes in a given list, modifying the list in place.
+ */
+static void
+_glcpp_parser_evaluate_defined_in_list (glcpp_parser_t *parser,
+ token_list_t *list)
+{
+ token_node_t *node, *node_prev, *replacement, *last = NULL;
+ int value;
+
+ if (list == NULL)
+ return;
+
+ node_prev = NULL;
+ node = list->head;
+
+ while (node) {
+
+ if (node->token->type != DEFINED)
+ goto NEXT;
+
+ value = _glcpp_parser_evaluate_defined (parser, node, &last);
+ if (value == -1)
+ goto NEXT;
+
+ replacement = ralloc (list, token_node_t);
+ replacement->token = _token_create_ival (list, INTEGER, value);
+
+ /* Splice replacement node into list, replacing from "node"
+ * through "last". */
+ if (node_prev)
+ node_prev->next = replacement;
+ else
+ list->head = replacement;
+ replacement->next = last->next;
+ if (last == list->tail)
+ list->tail = replacement;
+
+ node = replacement;
+
+ NEXT:
+ node_prev = node;
+ node = node->next;
+ }
+}
+
+/* Perform macro expansion on 'list', placing the resulting tokens
+ * into a new list which is initialized with a first token of type
+ * 'head_token_type'. Then begin lexing from the resulting list,
+ * (return to the current lexing source when this list is exhausted).
+ *
+ * See the documentation of _glcpp_parser_expand_token_list for a description
+ * of the "mode" parameter.
+ */
+static void
+_glcpp_parser_expand_and_lex_from (glcpp_parser_t *parser,
+ int head_token_type,
+ token_list_t *list,
+ expansion_mode_t mode)
+{
+ token_list_t *expanded;
+ token_t *token;
+
+ expanded = _token_list_create (parser);
+ token = _token_create_ival (parser, head_token_type, head_token_type);
+ _token_list_append (expanded, token);
+ _glcpp_parser_expand_token_list (parser, list, mode);
+ _token_list_append_list (expanded, list);
+ glcpp_parser_lex_from (parser, expanded);
+}
+
+static void
+_glcpp_parser_apply_pastes (glcpp_parser_t *parser, token_list_t *list)
+{
+ token_node_t *node;
+
+ node = list->head;
+ while (node)
+ {
+ token_node_t *next_non_space;
+
+ /* Look ahead for a PASTE token, skipping space. */
+ next_non_space = node->next;
+ while (next_non_space && next_non_space->token->type == SPACE)
+ next_non_space = next_non_space->next;
+
+ if (next_non_space == NULL)
+ break;
+
+ if (next_non_space->token->type != PASTE) {
+ node = next_non_space;
+ continue;
+ }
+
+ /* Now find the next non-space token after the PASTE. */
+ next_non_space = next_non_space->next;
+ while (next_non_space && next_non_space->token->type == SPACE)
+ next_non_space = next_non_space->next;
+
+ if (next_non_space == NULL) {
+ yyerror (&node->token->location, parser, "'##' cannot appear at either end of a macro expansion\n");
+ return;
+ }
+
+ node->token = _token_paste (parser, node->token, next_non_space->token);
+ node->next = next_non_space->next;
+ if (next_non_space == list->tail)
+ list->tail = node;
+ }
+
+ list->non_space_tail = list->tail;
+}
+
+/* This is a helper function that's essentially part of the
+ * implementation of _glcpp_parser_expand_node. It shouldn't be called
+ * except for by that function.
+ *
+ * Returns NULL if node is a simple token with no expansion, (that is,
+ * although 'node' corresponds to an identifier defined as a
+ * function-like macro, it is not followed with a parenthesized
+ * argument list).
+ *
+ * Compute the complete expansion of node (which is a function-like
+ * macro) and subsequent nodes which are arguments.
+ *
+ * Returns the token list that results from the expansion and sets
+ * *last to the last node in the list that was consumed by the
+ * expansion. Specifically, *last will be set as follows: as the
+ * token of the closing right parenthesis.
+ *
+ * See the documentation of _glcpp_parser_expand_token_list for a description
+ * of the "mode" parameter.
+ */
+static token_list_t *
+_glcpp_parser_expand_function (glcpp_parser_t *parser,
+ token_node_t *node,
+ token_node_t **last,
+ expansion_mode_t mode)
+{
+ macro_t *macro;
+ const char *identifier;
+ argument_list_t *arguments;
+ function_status_t status;
+ token_list_t *substituted;
+ int parameter_index;
+
+ identifier = node->token->value.str;
+
+ macro = hash_table_find (parser->defines, identifier);
+
+ assert (macro->is_function);
+
+ arguments = _argument_list_create (parser);
+ status = _arguments_parse (arguments, node, last);
+
+ switch (status) {
+ case FUNCTION_STATUS_SUCCESS:
+ break;
+ case FUNCTION_NOT_A_FUNCTION:
+ return NULL;
+ case FUNCTION_UNBALANCED_PARENTHESES:
+ glcpp_error (&node->token->location, parser, "Macro %s call has unbalanced parentheses\n", identifier);
+ return NULL;
+ }
+
+ /* Replace a macro defined as empty with a SPACE token. */
+ if (macro->replacements == NULL) {
+ ralloc_free (arguments);
+ return _token_list_create_with_one_space (parser);
+ }
+
+ if (! ((_argument_list_length (arguments) ==
+ _string_list_length (macro->parameters)) ||
+ (_string_list_length (macro->parameters) == 0 &&
+ _argument_list_length (arguments) == 1 &&
+ arguments->head->argument->head == NULL)))
+ {
+ glcpp_error (&node->token->location, parser,
+ "Error: macro %s invoked with %d arguments (expected %d)\n",
+ identifier,
+ _argument_list_length (arguments),
+ _string_list_length (macro->parameters));
+ return NULL;
+ }
+
+ /* Perform argument substitution on the replacement list. */
+ substituted = _token_list_create (arguments);
+
+ for (node = macro->replacements->head; node; node = node->next)
+ {
+ if (node->token->type == IDENTIFIER &&
+ _string_list_contains (macro->parameters,
+ node->token->value.str,
+ &parameter_index))
+ {
+ token_list_t *argument;
+ argument = _argument_list_member_at (arguments,
+ parameter_index);
+ /* Before substituting, we expand the argument
+ * tokens, or append a placeholder token for
+ * an empty argument. */
+ if (argument->head) {
+ token_list_t *expanded_argument;
+ expanded_argument = _token_list_copy (parser,
+ argument);
+ _glcpp_parser_expand_token_list (parser,
+ expanded_argument,
+ mode);
+ _token_list_append_list (substituted,
+ expanded_argument);
+ } else {
+ token_t *new_token;
+
+ new_token = _token_create_ival (substituted,
+ PLACEHOLDER,
+ PLACEHOLDER);
+ _token_list_append (substituted, new_token);
+ }
+ } else {
+ _token_list_append (substituted, node->token);
+ }
+ }
+
+ /* After argument substitution, and before further expansion
+ * below, implement token pasting. */
+
+ _token_list_trim_trailing_space (substituted);
+
+ _glcpp_parser_apply_pastes (parser, substituted);
+
+ return substituted;
+}
+
+/* Compute the complete expansion of node, (and subsequent nodes after
+ * 'node' in the case that 'node' is a function-like macro and
+ * subsequent nodes are arguments).
+ *
+ * Returns NULL if node is a simple token with no expansion.
+ *
+ * Otherwise, returns the token list that results from the expansion
+ * and sets *last to the last node in the list that was consumed by
+ * the expansion. Specifically, *last will be set as follows:
+ *
+ * As 'node' in the case of object-like macro expansion.
+ *
+ * As the token of the closing right parenthesis in the case of
+ * function-like macro expansion.
+ *
+ * See the documentation of _glcpp_parser_expand_token_list for a description
+ * of the "mode" parameter.
+ */
+static token_list_t *
+_glcpp_parser_expand_node (glcpp_parser_t *parser,
+ token_node_t *node,
+ token_node_t **last,
+ expansion_mode_t mode)
+{
+ token_t *token = node->token;
+ const char *identifier;
+ macro_t *macro;
+
+ /* We only expand identifiers */
+ if (token->type != IDENTIFIER) {
+ return NULL;
+ }
+
+ *last = node;
+ identifier = token->value.str;
+
+ /* Special handling for __LINE__ and __FILE__, (not through
+ * the hash table). */
+ if (strcmp(identifier, "__LINE__") == 0)
+ return _token_list_create_with_one_integer (parser, node->token->location.first_line);
+
+ if (strcmp(identifier, "__FILE__") == 0)
+ return _token_list_create_with_one_integer (parser, node->token->location.source);
+
+ /* Look up this identifier in the hash table. */
+ macro = hash_table_find (parser->defines, identifier);
+
+ /* Not a macro, so no expansion needed. */
+ if (macro == NULL)
+ return NULL;
+
+ /* Finally, don't expand this macro if we're already actively
+ * expanding it, (to avoid infinite recursion). */
+ if (_parser_active_list_contains (parser, identifier)) {
+ /* We change the token type here from IDENTIFIER to
+ * OTHER to prevent any future expansion of this
+ * unexpanded token. */
+ char *str;
+ token_list_t *expansion;
+ token_t *final;
+
+ str = ralloc_strdup (parser, token->value.str);
+ final = _token_create_str (parser, OTHER, str);
+ expansion = _token_list_create (parser);
+ _token_list_append (expansion, final);
+ return expansion;
+ }
+
+ if (! macro->is_function)
+ {
+ token_list_t *replacement;
+
+ /* Replace a macro defined as empty with a SPACE token. */
+ if (macro->replacements == NULL)
+ return _token_list_create_with_one_space (parser);
+
+ replacement = _token_list_copy (parser, macro->replacements);
+ _glcpp_parser_apply_pastes (parser, replacement);
+ return replacement;
+ }
+
+ return _glcpp_parser_expand_function (parser, node, last, mode);
+}
+
+/* Push a new identifier onto the parser's active list.
+ *
+ * Here, 'marker' is the token node that appears in the list after the
+ * expansion of 'identifier'. That is, when the list iterator begins
+ * examining 'marker', then it is time to pop this node from the
+ * active stack.
+ */
+static void
+_parser_active_list_push (glcpp_parser_t *parser,
+ const char *identifier,
+ token_node_t *marker)
+{
+ active_list_t *node;
+
+ node = ralloc (parser->active, active_list_t);
+ node->identifier = ralloc_strdup (node, identifier);
+ node->marker = marker;
+ node->next = parser->active;
+
+ parser->active = node;
+}
+
+static void
+_parser_active_list_pop (glcpp_parser_t *parser)
+{
+ active_list_t *node = parser->active;
+
+ if (node == NULL) {
+ parser->active = NULL;
+ return;
+ }
+
+ node = parser->active->next;
+ ralloc_free (parser->active);
+
+ parser->active = node;
+}
+
+static int
+_parser_active_list_contains (glcpp_parser_t *parser, const char *identifier)
+{
+ active_list_t *node;
+
+ if (parser->active == NULL)
+ return 0;
+
+ for (node = parser->active; node; node = node->next)
+ if (strcmp (node->identifier, identifier) == 0)
+ return 1;
+
+ return 0;
+}
+
+/* Walk over the token list replacing nodes with their expansion.
+ * Whenever nodes are expanded the walking will walk over the new
+ * nodes, continuing to expand as necessary. The results are placed in
+ * 'list' itself.
+ *
+ * The "mode" argument controls the handling of any DEFINED tokens that
+ * result from expansion as follows:
+ *
+ * EXPANSION_MODE_IGNORE_DEFINED: Any resulting DEFINED tokens will be
+ * left in the final list, unevaluated. This is the correct mode
+ * for expanding any list in any context other than a
+ * preprocessor conditional, (#if or #elif).
+ *
+ * EXPANSION_MODE_EVALUATE_DEFINED: Any resulting DEFINED tokens will be
+ * evaluated to 0 or 1 tokens depending on whether the following
+ * token is the name of a defined macro. If the DEFINED token is
+ * not followed by an (optionally parenthesized) identifier, then
+ * an error will be generated. This the correct mode for
+ * expanding any list in the context of a preprocessor
+ * conditional, (#if or #elif).
+ */
+static void
+_glcpp_parser_expand_token_list (glcpp_parser_t *parser,
+ token_list_t *list,
+ expansion_mode_t mode)
+{
+ token_node_t *node_prev;
+ token_node_t *node, *last = NULL;
+ token_list_t *expansion;
+ active_list_t *active_initial = parser->active;
+
+ if (list == NULL)
+ return;
+
+ _token_list_trim_trailing_space (list);
+
+ node_prev = NULL;
+ node = list->head;
+
+ if (mode == EXPANSION_MODE_EVALUATE_DEFINED)
+ _glcpp_parser_evaluate_defined_in_list (parser, list);
+
+ while (node) {
+
+ while (parser->active && parser->active->marker == node)
+ _parser_active_list_pop (parser);
+
+ expansion = _glcpp_parser_expand_node (parser, node, &last, mode);
+ if (expansion) {
+ token_node_t *n;
+
+ if (mode == EXPANSION_MODE_EVALUATE_DEFINED) {
+ _glcpp_parser_evaluate_defined_in_list (parser,
+ expansion);
+ }
+
+ for (n = node; n != last->next; n = n->next)
+ while (parser->active &&
+ parser->active->marker == n)
+ {
+ _parser_active_list_pop (parser);
+ }
+
+ _parser_active_list_push (parser,
+ node->token->value.str,
+ last->next);
+
+ /* Splice expansion into list, supporting a
+ * simple deletion if the expansion is
+ * empty. */
+ if (expansion->head) {
+ if (node_prev)
+ node_prev->next = expansion->head;
+ else
+ list->head = expansion->head;
+ expansion->tail->next = last->next;
+ if (last == list->tail)
+ list->tail = expansion->tail;
+ } else {
+ if (node_prev)
+ node_prev->next = last->next;
+ else
+ list->head = last->next;
+ if (last == list->tail)
+ list->tail = NULL;
+ }
+ } else {
+ node_prev = node;
+ }
+ node = node_prev ? node_prev->next : list->head;
+ }
+
+ /* Remove any lingering effects of this invocation on the
+ * active list. That is, pop until the list looks like it did
+ * at the beginning of this function. */
+ while (parser->active && parser->active != active_initial)
+ _parser_active_list_pop (parser);
+
+ list->non_space_tail = list->tail;
+}
+
+void
+_glcpp_parser_print_expanded_token_list (glcpp_parser_t *parser,
+ token_list_t *list)
+{
+ if (list == NULL)
+ return;
+
+ _glcpp_parser_expand_token_list (parser, list, EXPANSION_MODE_IGNORE_DEFINED);
+
+ _token_list_trim_trailing_space (list);
+
+ _token_list_print (parser, list);
+}
+
+static void
+_check_for_reserved_macro_name (glcpp_parser_t *parser, YYLTYPE *loc,
+ const char *identifier)
+{
+ /* Section 3.3 (Preprocessor) of the GLSL 1.30 spec (and later) and
+ * the GLSL ES spec (all versions) say:
+ *
+ * "All macro names containing two consecutive underscores ( __ )
+ * are reserved for future use as predefined macro names. All
+ * macro names prefixed with "GL_" ("GL" followed by a single
+ * underscore) are also reserved."
+ *
+ * The intention is that names containing __ are reserved for internal
+ * use by the implementation, and names prefixed with GL_ are reserved
+ * for use by Khronos. Since every extension adds a name prefixed
+ * with GL_ (i.e., the name of the extension), that should be an
+ * error. Names simply containing __ are dangerous to use, but should
+ * be allowed.
+ *
+ * A future version of the GLSL specification will clarify this.
+ */
+ if (strstr(identifier, "__")) {
+ glcpp_warning(loc, parser,
+ "Macro names containing \"__\" are reserved "
+ "for use by the implementation.\n");
+ }
+ if (strncmp(identifier, "GL_", 3) == 0) {
+ glcpp_error (loc, parser, "Macro names starting with \"GL_\" are reserved.\n");
+ }
+}
+
+static int
+_macro_equal (macro_t *a, macro_t *b)
+{
+ if (a->is_function != b->is_function)
+ return 0;
+
+ if (a->is_function) {
+ if (! _string_list_equal (a->parameters, b->parameters))
+ return 0;
+ }
+
+ return _token_list_equal_ignoring_space (a->replacements,
+ b->replacements);
+}
+
+void
+_define_object_macro (glcpp_parser_t *parser,
+ YYLTYPE *loc,
+ const char *identifier,
+ token_list_t *replacements)
+{
+ macro_t *macro, *previous;
+
+ /* We define pre-defined macros before we've started parsing the
+ * actual file. So if there's no location defined yet, that's what
+ * were doing and we don't want to generate an error for using the
+ * reserved names. */
+ if (loc != NULL)
+ _check_for_reserved_macro_name(parser, loc, identifier);
+
+ macro = ralloc (parser, macro_t);
+
+ macro->is_function = 0;
+ macro->parameters = NULL;
+ macro->identifier = ralloc_strdup (macro, identifier);
+ macro->replacements = replacements;
+ ralloc_steal (macro, replacements);
+
+ previous = hash_table_find (parser->defines, identifier);
+ if (previous) {
+ if (_macro_equal (macro, previous)) {
+ ralloc_free (macro);
+ return;
+ }
+ glcpp_error (loc, parser, "Redefinition of macro %s\n",
+ identifier);
+ }
+
+ hash_table_insert (parser->defines, macro, identifier);
+}
+
+void
+_define_function_macro (glcpp_parser_t *parser,
+ YYLTYPE *loc,
+ const char *identifier,
+ string_list_t *parameters,
+ token_list_t *replacements)
+{
+ macro_t *macro, *previous;
+ const char *dup;
+
+ _check_for_reserved_macro_name(parser, loc, identifier);
+
+ /* Check for any duplicate parameter names. */
+ if ((dup = _string_list_has_duplicate (parameters)) != NULL) {
+ glcpp_error (loc, parser, "Duplicate macro parameter \"%s\"",
+ dup);
+ }
+
+ macro = ralloc (parser, macro_t);
+ ralloc_steal (macro, parameters);
+ ralloc_steal (macro, replacements);
+
+ macro->is_function = 1;
+ macro->parameters = parameters;
+ macro->identifier = ralloc_strdup (macro, identifier);
+ macro->replacements = replacements;
+ previous = hash_table_find (parser->defines, identifier);
+ if (previous) {
+ if (_macro_equal (macro, previous)) {
+ ralloc_free (macro);
+ return;
+ }
+ glcpp_error (loc, parser, "Redefinition of macro %s\n",
+ identifier);
+ }
+
+ hash_table_insert (parser->defines, macro, identifier);
+}
+
+static int
+glcpp_parser_lex (YYSTYPE *yylval, YYLTYPE *yylloc, glcpp_parser_t *parser)
+{
+ token_node_t *node;
+ int ret;
+
+ if (parser->lex_from_list == NULL) {
+ ret = glcpp_lex (yylval, yylloc, parser->scanner);
+
+ /* XXX: This ugly block of code exists for the sole
+ * purpose of converting a NEWLINE token into a SPACE
+ * token, but only in the case where we have seen a
+ * function-like macro name, but have not yet seen its
+ * closing parenthesis.
+ *
+ * There's perhaps a more compact way to do this with
+ * mid-rule actions in the grammar.
+ *
+ * I'm definitely not pleased with the complexity of
+ * this code here.
+ */
+ if (parser->newline_as_space)
+ {
+ if (ret == '(') {
+ parser->paren_count++;
+ } else if (ret == ')') {
+ parser->paren_count--;
+ if (parser->paren_count == 0)
+ parser->newline_as_space = 0;
+ } else if (ret == NEWLINE) {
+ ret = SPACE;
+ } else if (ret != SPACE) {
+ if (parser->paren_count == 0)
+ parser->newline_as_space = 0;
+ }
+ }
+ else if (parser->in_control_line)
+ {
+ if (ret == NEWLINE)
+ parser->in_control_line = 0;
+ }
+ else if (ret == DEFINE_TOKEN ||
+ ret == UNDEF || ret == IF ||
+ ret == IFDEF || ret == IFNDEF ||
+ ret == ELIF || ret == ELSE ||
+ ret == ENDIF || ret == HASH_TOKEN)
+ {
+ parser->in_control_line = 1;
+ }
+ else if (ret == IDENTIFIER)
+ {
+ macro_t *macro;
+ macro = hash_table_find (parser->defines,
+ yylval->str);
+ if (macro && macro->is_function) {
+ parser->newline_as_space = 1;
+ parser->paren_count = 0;
+ }
+ }
+
+ return ret;
+ }
+
+ node = parser->lex_from_node;
+
+ if (node == NULL) {
+ ralloc_free (parser->lex_from_list);
+ parser->lex_from_list = NULL;
+ return NEWLINE;
+ }
+
+ *yylval = node->token->value;
+ ret = node->token->type;
+
+ parser->lex_from_node = node->next;
+
+ return ret;
+}
+
+static void
+glcpp_parser_lex_from (glcpp_parser_t *parser, token_list_t *list)
+{
+ token_node_t *node;
+
+ assert (parser->lex_from_list == NULL);
+
+ /* Copy list, eliminating any space tokens. */
+ parser->lex_from_list = _token_list_create (parser);
+
+ for (node = list->head; node; node = node->next) {
+ if (node->token->type == SPACE)
+ continue;
+ _token_list_append (parser->lex_from_list, node->token);
+ }
+
+ ralloc_free (list);
+
+ parser->lex_from_node = parser->lex_from_list->head;
+
+ /* It's possible the list consisted of nothing but whitespace. */
+ if (parser->lex_from_node == NULL) {
+ ralloc_free (parser->lex_from_list);
+ parser->lex_from_list = NULL;
+ }
+}
+
+static void
+_glcpp_parser_skip_stack_push_if (glcpp_parser_t *parser, YYLTYPE *loc,
+ int condition)
+{
+ skip_type_t current = SKIP_NO_SKIP;
+ skip_node_t *node;
+
+ if (parser->skip_stack)
+ current = parser->skip_stack->type;
+
+ node = ralloc (parser, skip_node_t);
+ node->loc = *loc;
+
+ if (current == SKIP_NO_SKIP) {
+ if (condition)
+ node->type = SKIP_NO_SKIP;
+ else
+ node->type = SKIP_TO_ELSE;
+ } else {
+ node->type = SKIP_TO_ENDIF;
+ }
+
+ node->has_else = false;
+ node->next = parser->skip_stack;
+ parser->skip_stack = node;
+}
+
+static void
+_glcpp_parser_skip_stack_change_if (glcpp_parser_t *parser, YYLTYPE *loc,
+ const char *type, int condition)
+{
+ if (parser->skip_stack == NULL) {
+ glcpp_error (loc, parser, "#%s without #if\n", type);
+ return;
+ }
+
+ if (parser->skip_stack->type == SKIP_TO_ELSE) {
+ if (condition)
+ parser->skip_stack->type = SKIP_NO_SKIP;
+ } else {
+ parser->skip_stack->type = SKIP_TO_ENDIF;
+ }
+}
+
+static void
+_glcpp_parser_skip_stack_pop (glcpp_parser_t *parser, YYLTYPE *loc)
+{
+ skip_node_t *node;
+
+ if (parser->skip_stack == NULL) {
+ glcpp_error (loc, parser, "#endif without #if\n");
+ return;
+ }
+
+ node = parser->skip_stack;
+ parser->skip_stack = node->next;
+ ralloc_free (node);
+}
+
+static void
+_glcpp_parser_handle_version_declaration(glcpp_parser_t *parser, intmax_t version,
+ const char *es_identifier,
+ bool explicitly_set)
+{
+ const struct gl_extensions *extensions = parser->extensions;
+
+ if (parser->version_resolved)
+ return;
+
+ parser->version_resolved = true;
+
+ add_builtin_define (parser, "__VERSION__", version);
+
+ parser->is_gles = (version == 100) ||
+ (es_identifier &&
+ (strcmp(es_identifier, "es") == 0));
+
+ /* Add pre-defined macros. */
+ if (parser->is_gles) {
+ add_builtin_define(parser, "GL_ES", 1);
+ add_builtin_define(parser, "GL_EXT_separate_shader_objects", 1);
+ add_builtin_define(parser, "GL_EXT_draw_buffers", 1);
+
+ if (extensions != NULL) {
+ if (extensions->OES_EGL_image_external)
+ add_builtin_define(parser, "GL_OES_EGL_image_external", 1);
+ if (extensions->OES_standard_derivatives)
+ add_builtin_define(parser, "GL_OES_standard_derivatives", 1);
+ if (extensions->ARB_texture_multisample)
+ add_builtin_define(parser, "GL_OES_texture_storage_multisample_2d_array", 1);
+ if (extensions->ARB_blend_func_extended)
+ add_builtin_define(parser, "GL_EXT_blend_func_extended", 1);
+ }
+ } else {
+ add_builtin_define(parser, "GL_ARB_draw_buffers", 1);
+ add_builtin_define(parser, "GL_ARB_enhanced_layouts", 1);
+ add_builtin_define(parser, "GL_ARB_separate_shader_objects", 1);
+ add_builtin_define(parser, "GL_ARB_texture_rectangle", 1);
+ add_builtin_define(parser, "GL_AMD_shader_trinary_minmax", 1);
+
+
+ if (extensions != NULL) {
+ if (extensions->EXT_texture_array)
+ add_builtin_define(parser, "GL_EXT_texture_array", 1);
+
+ if (extensions->ARB_arrays_of_arrays)
+ add_builtin_define(parser, "GL_ARB_arrays_of_arrays", 1);
+
+ if (extensions->ARB_fragment_coord_conventions)
+ add_builtin_define(parser, "GL_ARB_fragment_coord_conventions",
+ 1);
+
+ if (extensions->ARB_fragment_layer_viewport)
+ add_builtin_define(parser, "GL_ARB_fragment_layer_viewport", 1);
+
+ if (extensions->ARB_explicit_attrib_location)
+ add_builtin_define(parser, "GL_ARB_explicit_attrib_location", 1);
+
+ if (extensions->ARB_explicit_uniform_location)
+ add_builtin_define(parser, "GL_ARB_explicit_uniform_location", 1);
+
+ if (extensions->ARB_shader_texture_lod)
+ add_builtin_define(parser, "GL_ARB_shader_texture_lod", 1);
+
+ if (extensions->ARB_draw_instanced)
+ add_builtin_define(parser, "GL_ARB_draw_instanced", 1);
+
+ if (extensions->ARB_conservative_depth) {
+ add_builtin_define(parser, "GL_AMD_conservative_depth", 1);
+ add_builtin_define(parser, "GL_ARB_conservative_depth", 1);
+ }
+
+ if (extensions->ARB_shader_bit_encoding)
+ add_builtin_define(parser, "GL_ARB_shader_bit_encoding", 1);
+
+ if (extensions->ARB_shader_clock)
+ add_builtin_define(parser, "GL_ARB_shader_clock", 1);
+
+ if (extensions->ARB_uniform_buffer_object)
+ add_builtin_define(parser, "GL_ARB_uniform_buffer_object", 1);
+
+ if (extensions->ARB_texture_cube_map_array)
+ add_builtin_define(parser, "GL_ARB_texture_cube_map_array", 1);
+
+ if (extensions->ARB_shading_language_packing)
+ add_builtin_define(parser, "GL_ARB_shading_language_packing", 1);
+
+ if (extensions->ARB_texture_multisample)
+ add_builtin_define(parser, "GL_ARB_texture_multisample", 1);
+
+ if (extensions->ARB_texture_query_levels)
+ add_builtin_define(parser, "GL_ARB_texture_query_levels", 1);
+
+ if (extensions->ARB_texture_query_lod)
+ add_builtin_define(parser, "GL_ARB_texture_query_lod", 1);
+
+ if (extensions->ARB_gpu_shader5)
+ add_builtin_define(parser, "GL_ARB_gpu_shader5", 1);
+
+ if (extensions->ARB_gpu_shader_fp64)
+ add_builtin_define(parser, "GL_ARB_gpu_shader_fp64", 1);
+
+ if (extensions->ARB_vertex_attrib_64bit)
+ add_builtin_define(parser, "GL_ARB_vertex_attrib_64bit", 1);
+
+ if (extensions->AMD_vertex_shader_layer)
+ add_builtin_define(parser, "GL_AMD_vertex_shader_layer", 1);
+
+ if (extensions->AMD_vertex_shader_viewport_index)
+ add_builtin_define(parser, "GL_AMD_vertex_shader_viewport_index", 1);
+
+ if (extensions->ARB_shading_language_420pack)
+ add_builtin_define(parser, "GL_ARB_shading_language_420pack", 1);
+
+ if (extensions->ARB_sample_shading)
+ add_builtin_define(parser, "GL_ARB_sample_shading", 1);
+
+ if (extensions->ARB_texture_gather)
+ add_builtin_define(parser, "GL_ARB_texture_gather", 1);
+
+ if (extensions->ARB_shader_atomic_counters)
+ add_builtin_define(parser, "GL_ARB_shader_atomic_counters", 1);
+
+ if (extensions->ARB_viewport_array)
+ add_builtin_define(parser, "GL_ARB_viewport_array", 1);
+
+ if (extensions->ARB_compute_shader)
+ add_builtin_define(parser, "GL_ARB_compute_shader", 1);
+
+ if (extensions->ARB_shader_image_load_store)
+ add_builtin_define(parser, "GL_ARB_shader_image_load_store", 1);
+
+ if (extensions->ARB_shader_image_size)
+ add_builtin_define(parser, "GL_ARB_shader_image_size", 1);
+
+ if (extensions->ARB_shader_texture_image_samples)
+ add_builtin_define(parser, "GL_ARB_shader_texture_image_samples", 1);
+
+ if (extensions->ARB_derivative_control)
+ add_builtin_define(parser, "GL_ARB_derivative_control", 1);
+
+ if (extensions->ARB_shader_precision)
+ add_builtin_define(parser, "GL_ARB_shader_precision", 1);
+
+ if (extensions->ARB_shader_storage_buffer_object)
+ add_builtin_define(parser, "GL_ARB_shader_storage_buffer_object", 1);
+
+ if (extensions->ARB_tessellation_shader)
+ add_builtin_define(parser, "GL_ARB_tessellation_shader", 1);
+
+ if (extensions->ARB_shader_subroutine)
+ add_builtin_define(parser, "GL_ARB_shader_subroutine", 1);
+
+ if (extensions->ARB_shader_draw_parameters)
+ add_builtin_define(parser, "GL_ARB_shader_draw_parameters", 1);
+ }
+ }
+
+ if (extensions != NULL) {
+ if (extensions->EXT_shader_integer_mix)
+ add_builtin_define(parser, "GL_EXT_shader_integer_mix", 1);
+
+ if (extensions->EXT_shader_samples_identical)
+ add_builtin_define(parser, "GL_EXT_shader_samples_identical", 1);
+ }
+
+ if (version >= 150)
+ add_builtin_define(parser, "GL_core_profile", 1);
+
+ /* Currently, all ES2/ES3 implementations support highp in the
+ * fragment shader, so we always define this macro in ES2/ES3.
+ * If we ever get a driver that doesn't support highp, we'll
+ * need to add a flag to the gl_context and check that here.
+ */
+ if (version >= 130 || parser->is_gles)
+ add_builtin_define (parser, "GL_FRAGMENT_PRECISION_HIGH", 1);
+
+ if (explicitly_set) {
+ ralloc_asprintf_rewrite_tail (&parser->output, &parser->output_length,
+ "#version %" PRIiMAX "%s%s", version,
+ es_identifier ? " " : "",
+ es_identifier ? es_identifier : "");
+ }
+}
+
+/* GLSL version if no version is explicitly specified. */
+#define IMPLICIT_GLSL_VERSION 110
+
+/* GLSL ES version if no version is explicitly specified. */
+#define IMPLICIT_GLSL_ES_VERSION 100
+
+void
+glcpp_parser_resolve_implicit_version(glcpp_parser_t *parser)
+{
+ int language_version = parser->api == API_OPENGLES2 ?
+ IMPLICIT_GLSL_ES_VERSION :
+ IMPLICIT_GLSL_VERSION;
+
+ _glcpp_parser_handle_version_declaration(parser, language_version,
+ NULL, false);
+}
diff --git a/src/compiler/glsl/glcpp/glcpp.c b/src/compiler/glsl/glcpp/glcpp.c
new file mode 100644
index 00000000000..c62f4efec9d
--- /dev/null
+++ b/src/compiler/glsl/glcpp/glcpp.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <getopt.h>
+
+#include "glcpp.h"
+#include "main/mtypes.h"
+#include "main/shaderobj.h"
+#include "util/strtod.h"
+
+extern int glcpp_parser_debug;
+
+void
+_mesa_reference_shader(struct gl_context *ctx, struct gl_shader **ptr,
+ struct gl_shader *sh)
+{
+ (void) ctx;
+ *ptr = sh;
+}
+
+/* Read from fp until EOF and return a string of everything read.
+ */
+static char *
+load_text_fp (void *ctx, FILE *fp)
+{
+#define CHUNK 4096
+ char *text = NULL;
+ size_t text_size = 0;
+ size_t total_read = 0;
+ size_t bytes;
+
+ while (1) {
+ if (total_read + CHUNK + 1 > text_size) {
+ text_size = text_size ? text_size * 2 : CHUNK + 1;
+ text = reralloc_size (ctx, text, text_size);
+ if (text == NULL) {
+ fprintf (stderr, "Out of memory\n");
+ return NULL;
+ }
+ }
+ bytes = fread (text + total_read, 1, CHUNK, fp);
+ total_read += bytes;
+
+ if (bytes < CHUNK) {
+ break;
+ }
+ }
+
+ text[total_read] = '\0';
+
+ return text;
+}
+
+static char *
+load_text_file(void *ctx, const char *filename)
+{
+ char *text;
+ FILE *fp;
+
+ if (filename == NULL || strcmp (filename, "-") == 0)
+ return load_text_fp (ctx, stdin);
+
+ fp = fopen (filename, "r");
+ if (fp == NULL) {
+ fprintf (stderr, "Failed to open file %s: %s\n",
+ filename, strerror (errno));
+ return NULL;
+ }
+
+ text = load_text_fp (ctx, fp);
+
+ fclose(fp);
+
+ return text;
+}
+
+/* Initialize only those things that glcpp cares about.
+ */
+static void
+init_fake_gl_context (struct gl_context *gl_ctx)
+{
+ gl_ctx->API = API_OPENGL_COMPAT;
+ gl_ctx->Const.DisableGLSLLineContinuations = false;
+}
+
+static void
+usage (void)
+{
+ fprintf (stderr,
+ "Usage: glcpp [OPTIONS] [--] [<filename>]\n"
+ "\n"
+ "Pre-process the given filename (stdin if no filename given).\n"
+ "The following options are supported:\n"
+ " --disable-line-continuations Do not interpret lines ending with a\n"
+ " backslash ('\\') as a line continuation.\n");
+}
+
+enum {
+ DISABLE_LINE_CONTINUATIONS_OPT = CHAR_MAX + 1
+};
+
+static const struct option
+long_options[] = {
+ {"disable-line-continuations", no_argument, 0, DISABLE_LINE_CONTINUATIONS_OPT },
+ {"debug", no_argument, 0, 'd'},
+ {0, 0, 0, 0 }
+};
+
+int
+main (int argc, char *argv[])
+{
+ char *filename = NULL;
+ void *ctx = ralloc(NULL, void*);
+ char *info_log = ralloc_strdup(ctx, "");
+ const char *shader;
+ int ret;
+ struct gl_context gl_ctx;
+ int c;
+
+ init_fake_gl_context (&gl_ctx);
+
+ while ((c = getopt_long(argc, argv, "d", long_options, NULL)) != -1) {
+ switch (c) {
+ case DISABLE_LINE_CONTINUATIONS_OPT:
+ gl_ctx.Const.DisableGLSLLineContinuations = true;
+ break;
+ case 'd':
+ glcpp_parser_debug = 1;
+ break;
+ default:
+ usage ();
+ exit (1);
+ }
+ }
+
+ if (optind + 1 < argc) {
+ printf ("Unexpected argument: %s\n", argv[optind+1]);
+ usage ();
+ exit (1);
+ }
+ if (optind < argc) {
+ filename = argv[optind];
+ }
+
+ shader = load_text_file (ctx, filename);
+ if (shader == NULL)
+ return 1;
+
+ _mesa_locale_init();
+
+ ret = glcpp_preprocess(ctx, &shader, &info_log, NULL, &gl_ctx);
+
+ printf("%s", shader);
+ fprintf(stderr, "%s", info_log);
+
+ ralloc_free(ctx);
+
+ return ret;
+}
diff --git a/src/compiler/glsl/glcpp/glcpp.h b/src/compiler/glsl/glcpp/glcpp.h
new file mode 100644
index 00000000000..70aa14b6ec0
--- /dev/null
+++ b/src/compiler/glsl/glcpp/glcpp.h
@@ -0,0 +1,251 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef GLCPP_H
+#define GLCPP_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "main/mtypes.h"
+
+#include "util/ralloc.h"
+
+#include "program/hash_table.h"
+
+#define yyscan_t void*
+
+/* Some data types used for parser values. */
+
+typedef struct expression_value {
+ intmax_t value;
+ char *undefined_macro;
+} expression_value_t;
+
+
+typedef struct string_node {
+ const char *str;
+ struct string_node *next;
+} string_node_t;
+
+typedef struct string_list {
+ string_node_t *head;
+ string_node_t *tail;
+} string_list_t;
+
+typedef struct token token_t;
+typedef struct token_list token_list_t;
+
+typedef union YYSTYPE
+{
+ intmax_t ival;
+ expression_value_t expression_value;
+ char *str;
+ string_list_t *string_list;
+ token_t *token;
+ token_list_t *token_list;
+} YYSTYPE;
+
+# define YYSTYPE_IS_TRIVIAL 1
+# define YYSTYPE_IS_DECLARED 1
+
+typedef struct YYLTYPE {
+ int first_line;
+ int first_column;
+ int last_line;
+ int last_column;
+ unsigned source;
+} YYLTYPE;
+# define YYLTYPE_IS_DECLARED 1
+# define YYLTYPE_IS_TRIVIAL 1
+
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+do { \
+ if (N) \
+ { \
+ (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC(Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC(Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC(Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC(Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC(Rhs, 0).last_column; \
+ } \
+ (Current).source = 0; \
+} while (0)
+
+struct token {
+ int type;
+ YYSTYPE value;
+ YYLTYPE location;
+};
+
+typedef struct token_node {
+ token_t *token;
+ struct token_node *next;
+} token_node_t;
+
+struct token_list {
+ token_node_t *head;
+ token_node_t *tail;
+ token_node_t *non_space_tail;
+};
+
+typedef struct argument_node {
+ token_list_t *argument;
+ struct argument_node *next;
+} argument_node_t;
+
+typedef struct argument_list {
+ argument_node_t *head;
+ argument_node_t *tail;
+} argument_list_t;
+
+typedef struct glcpp_parser glcpp_parser_t;
+
+typedef enum {
+ TOKEN_CLASS_IDENTIFIER,
+ TOKEN_CLASS_IDENTIFIER_FINALIZED,
+ TOKEN_CLASS_FUNC_MACRO,
+ TOKEN_CLASS_OBJ_MACRO
+} token_class_t;
+
+token_class_t
+glcpp_parser_classify_token (glcpp_parser_t *parser,
+ const char *identifier,
+ int *parameter_index);
+
+typedef struct {
+ int is_function;
+ string_list_t *parameters;
+ const char *identifier;
+ token_list_t *replacements;
+} macro_t;
+
+typedef struct expansion_node {
+ macro_t *macro;
+ token_node_t *replacements;
+ struct expansion_node *next;
+} expansion_node_t;
+
+typedef enum skip_type {
+ SKIP_NO_SKIP,
+ SKIP_TO_ELSE,
+ SKIP_TO_ENDIF
+} skip_type_t;
+
+typedef struct skip_node {
+ skip_type_t type;
+ bool has_else;
+ YYLTYPE loc; /* location of the initial #if/#elif/... */
+ struct skip_node *next;
+} skip_node_t;
+
+typedef struct active_list {
+ const char *identifier;
+ token_node_t *marker;
+ struct active_list *next;
+} active_list_t;
+
+struct glcpp_parser {
+ yyscan_t scanner;
+ struct hash_table *defines;
+ active_list_t *active;
+ int lexing_directive;
+ int space_tokens;
+ int last_token_was_newline;
+ int last_token_was_space;
+ int first_non_space_token_this_line;
+ int newline_as_space;
+ int in_control_line;
+ int paren_count;
+ int commented_newlines;
+ skip_node_t *skip_stack;
+ int skipping;
+ token_list_t *lex_from_list;
+ token_node_t *lex_from_node;
+ char *output;
+ char *info_log;
+ size_t output_length;
+ size_t info_log_length;
+ int error;
+ const struct gl_extensions *extensions;
+ gl_api api;
+ bool version_resolved;
+ bool has_new_line_number;
+ int new_line_number;
+ bool has_new_source_number;
+ int new_source_number;
+ bool is_gles;
+};
+
+struct gl_extensions;
+
+glcpp_parser_t *
+glcpp_parser_create (const struct gl_extensions *extensions, gl_api api);
+
+int
+glcpp_parser_parse (glcpp_parser_t *parser);
+
+void
+glcpp_parser_destroy (glcpp_parser_t *parser);
+
+void
+glcpp_parser_resolve_implicit_version(glcpp_parser_t *parser);
+
+int
+glcpp_preprocess(void *ralloc_ctx, const char **shader, char **info_log,
+ const struct gl_extensions *extensions, struct gl_context *g_ctx);
+
+/* Functions for writing to the info log */
+
+void
+glcpp_error (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...);
+
+void
+glcpp_warning (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...);
+
+/* Generated by glcpp-lex.l to glcpp-lex.c */
+
+int
+glcpp_lex_init_extra (glcpp_parser_t *parser, yyscan_t* scanner);
+
+void
+glcpp_lex_set_source_string(glcpp_parser_t *parser, const char *shader);
+
+int
+glcpp_lex (YYSTYPE *lvalp, YYLTYPE *llocp, yyscan_t scanner);
+
+int
+glcpp_lex_destroy (yyscan_t scanner);
+
+/* Generated by glcpp-parse.y to glcpp-parse.c */
+
+int
+yyparse (glcpp_parser_t *parser);
+
+#endif
diff --git a/src/compiler/glsl/glcpp/pp.c b/src/compiler/glsl/glcpp/pp.c
new file mode 100644
index 00000000000..160c6662ff6
--- /dev/null
+++ b/src/compiler/glsl/glcpp/pp.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include "glcpp.h"
+
+void
+glcpp_error (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...)
+{
+ va_list ap;
+
+ parser->error = 1;
+ ralloc_asprintf_rewrite_tail(&parser->info_log,
+ &parser->info_log_length,
+ "%u:%u(%u): "
+ "preprocessor error: ",
+ locp->source,
+ locp->first_line,
+ locp->first_column);
+ va_start(ap, fmt);
+ ralloc_vasprintf_rewrite_tail(&parser->info_log,
+ &parser->info_log_length,
+ fmt, ap);
+ va_end(ap);
+ ralloc_asprintf_rewrite_tail(&parser->info_log,
+ &parser->info_log_length, "\n");
+}
+
+void
+glcpp_warning (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...)
+{
+ va_list ap;
+
+ ralloc_asprintf_rewrite_tail(&parser->info_log,
+ &parser->info_log_length,
+ "%u:%u(%u): "
+ "preprocessor warning: ",
+ locp->source,
+ locp->first_line,
+ locp->first_column);
+ va_start(ap, fmt);
+ ralloc_vasprintf_rewrite_tail(&parser->info_log,
+ &parser->info_log_length,
+ fmt, ap);
+ va_end(ap);
+ ralloc_asprintf_rewrite_tail(&parser->info_log,
+ &parser->info_log_length, "\n");
+}
+
+/* Given str, (that's expected to start with a newline terminator of some
+ * sort), return a pointer to the first character in str after the newline.
+ *
+ * A newline terminator can be any of the following sequences:
+ *
+ * "\r\n"
+ * "\n\r"
+ * "\n"
+ * "\r"
+ *
+ * And the longest such sequence will be skipped.
+ */
+static const char *
+skip_newline (const char *str)
+{
+ const char *ret = str;
+
+ if (ret == NULL)
+ return ret;
+
+ if (*ret == '\0')
+ return ret;
+
+ if (*ret == '\r') {
+ ret++;
+ if (*ret && *ret == '\n')
+ ret++;
+ } else if (*ret == '\n') {
+ ret++;
+ if (*ret && *ret == '\r')
+ ret++;
+ }
+
+ return ret;
+}
+
+/* Remove any line continuation characters in the shader, (whether in
+ * preprocessing directives or in GLSL code).
+ */
+static char *
+remove_line_continuations(glcpp_parser_t *ctx, const char *shader)
+{
+ char *clean = ralloc_strdup(ctx, "");
+ const char *backslash, *newline, *search_start;
+ const char *cr, *lf;
+ char newline_separator[3];
+ int collapsed_newlines = 0;
+
+ search_start = shader;
+
+ /* Determine what flavor of newlines this shader is using. GLSL
+ * provides for 4 different possible ways to separate lines, (using
+ * one or two characters):
+ *
+ * "\n" (line-feed, like Linux, Unix, and new Mac OS)
+ * "\r" (carriage-return, like old Mac files)
+ * "\r\n" (carriage-return + line-feed, like DOS files)
+ * "\n\r" (line-feed + carriage-return, like nothing, really)
+ *
+ * This code explicitly supports a shader that uses a mixture of
+ * newline terminators and will properly handle line continuation
+ * backslashes followed by any of the above.
+ *
+ * But, since we must also insert additional newlines in the output
+ * (for any collapsed lines) we attempt to maintain consistency by
+ * examining the first encountered newline terminator, and using the
+ * same terminator for any newlines we insert.
+ */
+ cr = strchr(search_start, '\r');
+ lf = strchr(search_start, '\n');
+
+ newline_separator[0] = '\n';
+ newline_separator[1] = '\0';
+ newline_separator[2] = '\0';
+
+ if (cr == NULL) {
+ /* Nothing to do. */
+ } else if (lf == NULL) {
+ newline_separator[0] = '\r';
+ } else if (lf == cr + 1) {
+ newline_separator[0] = '\r';
+ newline_separator[1] = '\n';
+ } else if (cr == lf + 1) {
+ newline_separator[0] = '\n';
+ newline_separator[1] = '\r';
+ }
+
+ while (true) {
+ backslash = strchr(search_start, '\\');
+
+ /* If we have previously collapsed any line-continuations,
+ * then we want to insert additional newlines at the next
+ * occurrence of a newline character to avoid changing any
+ * line numbers.
+ */
+ if (collapsed_newlines) {
+ cr = strchr (search_start, '\r');
+ lf = strchr (search_start, '\n');
+ if (cr && lf)
+ newline = cr < lf ? cr : lf;
+ else if (cr)
+ newline = cr;
+ else
+ newline = lf;
+ if (newline &&
+ (backslash == NULL || newline < backslash))
+ {
+ ralloc_strncat(&clean, shader,
+ newline - shader + 1);
+ while (collapsed_newlines) {
+ ralloc_strcat(&clean, newline_separator);
+ collapsed_newlines--;
+ }
+ shader = skip_newline (newline);
+ search_start = shader;
+ }
+ }
+
+ search_start = backslash + 1;
+
+ if (backslash == NULL)
+ break;
+
+ /* At each line continuation, (backslash followed by a
+ * newline), copy all preceding text to the output, then
+ * advance the shader pointer to the character after the
+ * newline.
+ */
+ if (backslash[1] == '\r' || backslash[1] == '\n')
+ {
+ collapsed_newlines++;
+ ralloc_strncat(&clean, shader, backslash - shader);
+ shader = skip_newline (backslash + 1);
+ search_start = shader;
+ }
+ }
+
+ ralloc_strcat(&clean, shader);
+
+ return clean;
+}
+
+int
+glcpp_preprocess(void *ralloc_ctx, const char **shader, char **info_log,
+ const struct gl_extensions *extensions, struct gl_context *gl_ctx)
+{
+ int errors;
+ glcpp_parser_t *parser = glcpp_parser_create (extensions, gl_ctx->API);
+
+ if (! gl_ctx->Const.DisableGLSLLineContinuations)
+ *shader = remove_line_continuations(parser, *shader);
+
+ glcpp_lex_set_source_string (parser, *shader);
+
+ glcpp_parser_parse (parser);
+
+ if (parser->skip_stack)
+ glcpp_error (&parser->skip_stack->loc, parser, "Unterminated #if\n");
+
+ glcpp_parser_resolve_implicit_version(parser);
+
+ ralloc_strcat(info_log, parser->info_log);
+
+ ralloc_steal(ralloc_ctx, parser->output);
+ *shader = parser->output;
+
+ errors = parser->error;
+ glcpp_parser_destroy (parser);
+ return errors;
+}
diff --git a/src/compiler/glsl/glcpp/tests/.gitignore b/src/compiler/glsl/glcpp/tests/.gitignore
new file mode 100644
index 00000000000..3802c850a3e
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/.gitignore
@@ -0,0 +1,4 @@
+subtest-cr/
+subtest-lf/
+subtest-cr-lf/
+subtest-lf-cr/
diff --git a/src/compiler/glsl/glcpp/tests/000-content-with-spaces.c b/src/compiler/glsl/glcpp/tests/000-content-with-spaces.c
new file mode 100644
index 00000000000..1f2320e6fc1
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/000-content-with-spaces.c
@@ -0,0 +1 @@
+ this is four tokens with spaces
diff --git a/src/compiler/glsl/glcpp/tests/000-content-with-spaces.c.expected b/src/compiler/glsl/glcpp/tests/000-content-with-spaces.c.expected
new file mode 100644
index 00000000000..00791910ed5
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/000-content-with-spaces.c.expected
@@ -0,0 +1 @@
+ this is four tokens with spaces
diff --git a/src/compiler/glsl/glcpp/tests/001-define.c b/src/compiler/glsl/glcpp/tests/001-define.c
new file mode 100644
index 00000000000..cbf2fee0e75
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/001-define.c
@@ -0,0 +1,2 @@
+#define foo 1
+foo
diff --git a/src/compiler/glsl/glcpp/tests/001-define.c.expected b/src/compiler/glsl/glcpp/tests/001-define.c.expected
new file mode 100644
index 00000000000..a464d9da742
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/001-define.c.expected
@@ -0,0 +1,2 @@
+
+1
diff --git a/src/compiler/glsl/glcpp/tests/002-define-chain.c b/src/compiler/glsl/glcpp/tests/002-define-chain.c
new file mode 100644
index 00000000000..87d75c68751
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/002-define-chain.c
@@ -0,0 +1,3 @@
+#define foo 1
+#define bar foo
+bar
diff --git a/src/compiler/glsl/glcpp/tests/002-define-chain.c.expected b/src/compiler/glsl/glcpp/tests/002-define-chain.c.expected
new file mode 100644
index 00000000000..c6c9ee38a9e
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/002-define-chain.c.expected
@@ -0,0 +1,3 @@
+
+
+1
diff --git a/src/compiler/glsl/glcpp/tests/003-define-chain-reverse.c b/src/compiler/glsl/glcpp/tests/003-define-chain-reverse.c
new file mode 100644
index 00000000000..a18b724eca0
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/003-define-chain-reverse.c
@@ -0,0 +1,3 @@
+#define bar foo
+#define foo 1
+bar
diff --git a/src/compiler/glsl/glcpp/tests/003-define-chain-reverse.c.expected b/src/compiler/glsl/glcpp/tests/003-define-chain-reverse.c.expected
new file mode 100644
index 00000000000..c6c9ee38a9e
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/003-define-chain-reverse.c.expected
@@ -0,0 +1,3 @@
+
+
+1
diff --git a/src/compiler/glsl/glcpp/tests/004-define-recursive.c b/src/compiler/glsl/glcpp/tests/004-define-recursive.c
new file mode 100644
index 00000000000..2ac56ea3dcf
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/004-define-recursive.c
@@ -0,0 +1,6 @@
+#define foo bar
+#define bar baz
+#define baz foo
+foo
+bar
+baz
diff --git a/src/compiler/glsl/glcpp/tests/004-define-recursive.c.expected b/src/compiler/glsl/glcpp/tests/004-define-recursive.c.expected
new file mode 100644
index 00000000000..2d07687f8ca
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/004-define-recursive.c.expected
@@ -0,0 +1,6 @@
+
+
+
+foo
+bar
+baz
diff --git a/src/compiler/glsl/glcpp/tests/005-define-composite-chain.c b/src/compiler/glsl/glcpp/tests/005-define-composite-chain.c
new file mode 100644
index 00000000000..f5521df968d
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/005-define-composite-chain.c
@@ -0,0 +1,3 @@
+#define foo 1
+#define bar a foo
+bar
diff --git a/src/compiler/glsl/glcpp/tests/005-define-composite-chain.c.expected b/src/compiler/glsl/glcpp/tests/005-define-composite-chain.c.expected
new file mode 100644
index 00000000000..892975c268c
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/005-define-composite-chain.c.expected
@@ -0,0 +1,3 @@
+
+
+a 1
diff --git a/src/compiler/glsl/glcpp/tests/006-define-composite-chain-reverse.c b/src/compiler/glsl/glcpp/tests/006-define-composite-chain-reverse.c
new file mode 100644
index 00000000000..4bb91a1221a
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/006-define-composite-chain-reverse.c
@@ -0,0 +1,3 @@
+#define bar a foo
+#define foo 1
+bar
diff --git a/src/compiler/glsl/glcpp/tests/006-define-composite-chain-reverse.c.expected b/src/compiler/glsl/glcpp/tests/006-define-composite-chain-reverse.c.expected
new file mode 100644
index 00000000000..892975c268c
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/006-define-composite-chain-reverse.c.expected
@@ -0,0 +1,3 @@
+
+
+a 1
diff --git a/src/compiler/glsl/glcpp/tests/007-define-composite-recursive.c b/src/compiler/glsl/glcpp/tests/007-define-composite-recursive.c
new file mode 100644
index 00000000000..5784565bdf3
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/007-define-composite-recursive.c
@@ -0,0 +1,6 @@
+#define foo a bar
+#define bar b baz
+#define baz c foo
+foo
+bar
+baz
diff --git a/src/compiler/glsl/glcpp/tests/007-define-composite-recursive.c.expected b/src/compiler/glsl/glcpp/tests/007-define-composite-recursive.c.expected
new file mode 100644
index 00000000000..0b0b477d9df
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/007-define-composite-recursive.c.expected
@@ -0,0 +1,6 @@
+
+
+
+a b c foo
+b c a bar
+c a b baz
diff --git a/src/compiler/glsl/glcpp/tests/008-define-empty.c b/src/compiler/glsl/glcpp/tests/008-define-empty.c
new file mode 100644
index 00000000000..b1bd17ec215
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/008-define-empty.c
@@ -0,0 +1,2 @@
+#define foo
+foo
diff --git a/src/compiler/glsl/glcpp/tests/008-define-empty.c.expected b/src/compiler/glsl/glcpp/tests/008-define-empty.c.expected
new file mode 100644
index 00000000000..d148bc8e800
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/008-define-empty.c.expected
@@ -0,0 +1,2 @@
+
+
diff --git a/src/compiler/glsl/glcpp/tests/009-undef.c b/src/compiler/glsl/glcpp/tests/009-undef.c
new file mode 100644
index 00000000000..3fc1fb44243
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/009-undef.c
@@ -0,0 +1,4 @@
+#define foo 1
+foo
+#undef foo
+foo
diff --git a/src/compiler/glsl/glcpp/tests/009-undef.c.expected b/src/compiler/glsl/glcpp/tests/009-undef.c.expected
new file mode 100644
index 00000000000..9c0b35a4518
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/009-undef.c.expected
@@ -0,0 +1,4 @@
+
+1
+
+foo
diff --git a/src/compiler/glsl/glcpp/tests/010-undef-re-define.c b/src/compiler/glsl/glcpp/tests/010-undef-re-define.c
new file mode 100644
index 00000000000..32ff73798b1
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/010-undef-re-define.c
@@ -0,0 +1,6 @@
+#define foo 1
+foo
+#undef foo
+foo
+#define foo 2
+foo
diff --git a/src/compiler/glsl/glcpp/tests/010-undef-re-define.c.expected b/src/compiler/glsl/glcpp/tests/010-undef-re-define.c.expected
new file mode 100644
index 00000000000..5970f49028e
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/010-undef-re-define.c.expected
@@ -0,0 +1,6 @@
+
+1
+
+foo
+
+2
diff --git a/src/compiler/glsl/glcpp/tests/011-define-func-empty.c b/src/compiler/glsl/glcpp/tests/011-define-func-empty.c
new file mode 100644
index 00000000000..d9ce13c2284
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/011-define-func-empty.c
@@ -0,0 +1,2 @@
+#define foo()
+foo()
diff --git a/src/compiler/glsl/glcpp/tests/011-define-func-empty.c.expected b/src/compiler/glsl/glcpp/tests/011-define-func-empty.c.expected
new file mode 100644
index 00000000000..d148bc8e800
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/011-define-func-empty.c.expected
@@ -0,0 +1,2 @@
+
+
diff --git a/src/compiler/glsl/glcpp/tests/012-define-func-no-args.c b/src/compiler/glsl/glcpp/tests/012-define-func-no-args.c
new file mode 100644
index 00000000000..c2bb730b115
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/012-define-func-no-args.c
@@ -0,0 +1,2 @@
+#define foo() bar
+foo()
diff --git a/src/compiler/glsl/glcpp/tests/012-define-func-no-args.c.expected b/src/compiler/glsl/glcpp/tests/012-define-func-no-args.c.expected
new file mode 100644
index 00000000000..9f075f26004
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/012-define-func-no-args.c.expected
@@ -0,0 +1,2 @@
+
+bar
diff --git a/src/compiler/glsl/glcpp/tests/013-define-func-1-arg-unused.c b/src/compiler/glsl/glcpp/tests/013-define-func-1-arg-unused.c
new file mode 100644
index 00000000000..f78fb8b118a
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/013-define-func-1-arg-unused.c
@@ -0,0 +1,2 @@
+#define foo(x) 1
+foo(bar)
diff --git a/src/compiler/glsl/glcpp/tests/013-define-func-1-arg-unused.c.expected b/src/compiler/glsl/glcpp/tests/013-define-func-1-arg-unused.c.expected
new file mode 100644
index 00000000000..a464d9da742
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/013-define-func-1-arg-unused.c.expected
@@ -0,0 +1,2 @@
+
+1
diff --git a/src/compiler/glsl/glcpp/tests/014-define-func-2-arg-unused.c b/src/compiler/glsl/glcpp/tests/014-define-func-2-arg-unused.c
new file mode 100644
index 00000000000..11feb2624b7
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/014-define-func-2-arg-unused.c
@@ -0,0 +1,2 @@
+#define foo(x,y) 1
+foo(bar,baz)
diff --git a/src/compiler/glsl/glcpp/tests/014-define-func-2-arg-unused.c.expected b/src/compiler/glsl/glcpp/tests/014-define-func-2-arg-unused.c.expected
new file mode 100644
index 00000000000..a464d9da742
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/014-define-func-2-arg-unused.c.expected
@@ -0,0 +1,2 @@
+
+1
diff --git a/src/compiler/glsl/glcpp/tests/015-define-object-with-parens.c b/src/compiler/glsl/glcpp/tests/015-define-object-with-parens.c
new file mode 100644
index 00000000000..558da9c617b
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/015-define-object-with-parens.c
@@ -0,0 +1,4 @@
+#define foo ()1
+foo()
+#define bar ()2
+bar()
diff --git a/src/compiler/glsl/glcpp/tests/015-define-object-with-parens.c.expected b/src/compiler/glsl/glcpp/tests/015-define-object-with-parens.c.expected
new file mode 100644
index 00000000000..a70321a4c51
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/015-define-object-with-parens.c.expected
@@ -0,0 +1,4 @@
+
+()1()
+
+()2()
diff --git a/src/compiler/glsl/glcpp/tests/016-define-func-1-arg.c b/src/compiler/glsl/glcpp/tests/016-define-func-1-arg.c
new file mode 100644
index 00000000000..a2e2404c7c1
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/016-define-func-1-arg.c
@@ -0,0 +1,2 @@
+#define foo(x) ((x)+1)
+foo(bar)
diff --git a/src/compiler/glsl/glcpp/tests/016-define-func-1-arg.c.expected b/src/compiler/glsl/glcpp/tests/016-define-func-1-arg.c.expected
new file mode 100644
index 00000000000..6bfe04f7381
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/016-define-func-1-arg.c.expected
@@ -0,0 +1,2 @@
+
+((bar)+1)
diff --git a/src/compiler/glsl/glcpp/tests/017-define-func-2-args.c b/src/compiler/glsl/glcpp/tests/017-define-func-2-args.c
new file mode 100644
index 00000000000..c7253835278
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/017-define-func-2-args.c
@@ -0,0 +1,2 @@
+#define foo(x,y) ((x)*(y))
+foo(bar,baz)
diff --git a/src/compiler/glsl/glcpp/tests/017-define-func-2-args.c.expected b/src/compiler/glsl/glcpp/tests/017-define-func-2-args.c.expected
new file mode 100644
index 00000000000..f7a2b8c26cb
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/017-define-func-2-args.c.expected
@@ -0,0 +1,2 @@
+
+((bar)*(baz))
diff --git a/src/compiler/glsl/glcpp/tests/018-define-func-macro-as-parameter.c b/src/compiler/glsl/glcpp/tests/018-define-func-macro-as-parameter.c
new file mode 100644
index 00000000000..668130b8f9b
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/018-define-func-macro-as-parameter.c
@@ -0,0 +1,3 @@
+#define x 0
+#define foo(x) x
+foo(1)
diff --git a/src/compiler/glsl/glcpp/tests/018-define-func-macro-as-parameter.c.expected b/src/compiler/glsl/glcpp/tests/018-define-func-macro-as-parameter.c.expected
new file mode 100644
index 00000000000..c6c9ee38a9e
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/018-define-func-macro-as-parameter.c.expected
@@ -0,0 +1,3 @@
+
+
+1
diff --git a/src/compiler/glsl/glcpp/tests/019-define-func-1-arg-multi.c b/src/compiler/glsl/glcpp/tests/019-define-func-1-arg-multi.c
new file mode 100644
index 00000000000..c4e62b25508
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/019-define-func-1-arg-multi.c
@@ -0,0 +1,2 @@
+#define foo(x) (x)
+foo(this is more than one word)
diff --git a/src/compiler/glsl/glcpp/tests/019-define-func-1-arg-multi.c.expected b/src/compiler/glsl/glcpp/tests/019-define-func-1-arg-multi.c.expected
new file mode 100644
index 00000000000..1e89b8cfd0c
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/019-define-func-1-arg-multi.c.expected
@@ -0,0 +1,2 @@
+
+(this is more than one word)
diff --git a/src/compiler/glsl/glcpp/tests/020-define-func-2-arg-multi.c b/src/compiler/glsl/glcpp/tests/020-define-func-2-arg-multi.c
new file mode 100644
index 00000000000..3049ad15465
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/020-define-func-2-arg-multi.c
@@ -0,0 +1,2 @@
+#define foo(x,y) x,two fish,red fish,y
+foo(one fish, blue fish)
diff --git a/src/compiler/glsl/glcpp/tests/020-define-func-2-arg-multi.c.expected b/src/compiler/glsl/glcpp/tests/020-define-func-2-arg-multi.c.expected
new file mode 100644
index 00000000000..19f59f5ecb7
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/020-define-func-2-arg-multi.c.expected
@@ -0,0 +1,2 @@
+
+one fish,two fish,red fish,blue fish
diff --git a/src/compiler/glsl/glcpp/tests/021-define-func-compose.c b/src/compiler/glsl/glcpp/tests/021-define-func-compose.c
new file mode 100644
index 00000000000..21ddd0e65f9
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/021-define-func-compose.c
@@ -0,0 +1,3 @@
+#define bar(x) (1+(x))
+#define foo(y) (2*(y))
+foo(bar(3))
diff --git a/src/compiler/glsl/glcpp/tests/021-define-func-compose.c.expected b/src/compiler/glsl/glcpp/tests/021-define-func-compose.c.expected
new file mode 100644
index 00000000000..87f51f0baca
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/021-define-func-compose.c.expected
@@ -0,0 +1,3 @@
+
+
+(2*((1+(3))))
diff --git a/src/compiler/glsl/glcpp/tests/022-define-func-arg-with-parens.c b/src/compiler/glsl/glcpp/tests/022-define-func-arg-with-parens.c
new file mode 100644
index 00000000000..c20d73a4a28
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/022-define-func-arg-with-parens.c
@@ -0,0 +1,2 @@
+#define foo(x) (x)
+foo(argument(including parens)for the win)
diff --git a/src/compiler/glsl/glcpp/tests/022-define-func-arg-with-parens.c.expected b/src/compiler/glsl/glcpp/tests/022-define-func-arg-with-parens.c.expected
new file mode 100644
index 00000000000..1dfc6698bb7
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/022-define-func-arg-with-parens.c.expected
@@ -0,0 +1,2 @@
+
+(argument(including parens)for the win)
diff --git a/src/compiler/glsl/glcpp/tests/023-define-extra-whitespace.c b/src/compiler/glsl/glcpp/tests/023-define-extra-whitespace.c
new file mode 100644
index 00000000000..7ebfed6516c
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/023-define-extra-whitespace.c
@@ -0,0 +1,8 @@
+#define noargs() 1
+# define onearg(foo) foo
+ # define twoargs( x , y ) x y
+ # define threeargs( a , b , c ) a b c
+noargs ( )
+onearg ( 2 )
+twoargs ( 3 , 4 )
+threeargs ( 5 , 6 , 7 )
diff --git a/src/compiler/glsl/glcpp/tests/023-define-extra-whitespace.c.expected b/src/compiler/glsl/glcpp/tests/023-define-extra-whitespace.c.expected
new file mode 100644
index 00000000000..9c58275d0f9
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/023-define-extra-whitespace.c.expected
@@ -0,0 +1,8 @@
+
+
+
+
+1
+2
+3 4
+5 6 7
diff --git a/src/compiler/glsl/glcpp/tests/024-define-chain-to-self-recursion.c b/src/compiler/glsl/glcpp/tests/024-define-chain-to-self-recursion.c
new file mode 100644
index 00000000000..e788adce30c
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/024-define-chain-to-self-recursion.c
@@ -0,0 +1,3 @@
+#define foo foo
+#define bar foo
+bar
diff --git a/src/compiler/glsl/glcpp/tests/024-define-chain-to-self-recursion.c.expected b/src/compiler/glsl/glcpp/tests/024-define-chain-to-self-recursion.c.expected
new file mode 100644
index 00000000000..15600af546b
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/024-define-chain-to-self-recursion.c.expected
@@ -0,0 +1,3 @@
+
+
+foo
diff --git a/src/compiler/glsl/glcpp/tests/025-func-macro-as-non-macro.c b/src/compiler/glsl/glcpp/tests/025-func-macro-as-non-macro.c
new file mode 100644
index 00000000000..b433671d1bf
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/025-func-macro-as-non-macro.c
@@ -0,0 +1,2 @@
+#define foo(bar) bar
+foo bar
diff --git a/src/compiler/glsl/glcpp/tests/025-func-macro-as-non-macro.c.expected b/src/compiler/glsl/glcpp/tests/025-func-macro-as-non-macro.c.expected
new file mode 100644
index 00000000000..4a59f0520e3
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/025-func-macro-as-non-macro.c.expected
@@ -0,0 +1,2 @@
+
+foo bar
diff --git a/src/compiler/glsl/glcpp/tests/026-define-func-extra-newlines.c b/src/compiler/glsl/glcpp/tests/026-define-func-extra-newlines.c
new file mode 100644
index 00000000000..0d837405309
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/026-define-func-extra-newlines.c
@@ -0,0 +1,6 @@
+#define foo(a) bar
+
+foo
+(
+1
+)
diff --git a/src/compiler/glsl/glcpp/tests/026-define-func-extra-newlines.c.expected b/src/compiler/glsl/glcpp/tests/026-define-func-extra-newlines.c.expected
new file mode 100644
index 00000000000..5e3c70f2cc5
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/026-define-func-extra-newlines.c.expected
@@ -0,0 +1,3 @@
+
+
+bar
diff --git a/src/compiler/glsl/glcpp/tests/027-define-chain-obj-to-func.c b/src/compiler/glsl/glcpp/tests/027-define-chain-obj-to-func.c
new file mode 100644
index 00000000000..5ccb52caba5
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/027-define-chain-obj-to-func.c
@@ -0,0 +1,3 @@
+#define failure() success
+#define foo failure()
+foo
diff --git a/src/compiler/glsl/glcpp/tests/027-define-chain-obj-to-func.c.expected b/src/compiler/glsl/glcpp/tests/027-define-chain-obj-to-func.c.expected
new file mode 100644
index 00000000000..94c15f95059
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/027-define-chain-obj-to-func.c.expected
@@ -0,0 +1,3 @@
+
+
+success
diff --git a/src/compiler/glsl/glcpp/tests/028-define-chain-obj-to-non-func.c b/src/compiler/glsl/glcpp/tests/028-define-chain-obj-to-non-func.c
new file mode 100644
index 00000000000..44962a71876
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/028-define-chain-obj-to-non-func.c
@@ -0,0 +1,3 @@
+#define success() failure
+#define foo success
+foo
diff --git a/src/compiler/glsl/glcpp/tests/028-define-chain-obj-to-non-func.c.expected b/src/compiler/glsl/glcpp/tests/028-define-chain-obj-to-non-func.c.expected
new file mode 100644
index 00000000000..94c15f95059
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/028-define-chain-obj-to-non-func.c.expected
@@ -0,0 +1,3 @@
+
+
+success
diff --git a/src/compiler/glsl/glcpp/tests/029-define-chain-obj-to-func-with-args.c b/src/compiler/glsl/glcpp/tests/029-define-chain-obj-to-func-with-args.c
new file mode 100644
index 00000000000..261f7d28fc2
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/029-define-chain-obj-to-func-with-args.c
@@ -0,0 +1,3 @@
+#define bar(failure) failure
+#define foo bar(success)
+foo
diff --git a/src/compiler/glsl/glcpp/tests/029-define-chain-obj-to-func-with-args.c.expected b/src/compiler/glsl/glcpp/tests/029-define-chain-obj-to-func-with-args.c.expected
new file mode 100644
index 00000000000..94c15f95059
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/029-define-chain-obj-to-func-with-args.c.expected
@@ -0,0 +1,3 @@
+
+
+success
diff --git a/src/compiler/glsl/glcpp/tests/030-define-chain-obj-to-func-compose.c b/src/compiler/glsl/glcpp/tests/030-define-chain-obj-to-func-compose.c
new file mode 100644
index 00000000000..e56fbefd62d
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/030-define-chain-obj-to-func-compose.c
@@ -0,0 +1,4 @@
+#define baz(failure) failure
+#define bar(failure) failure
+#define foo bar(baz(success))
+foo
diff --git a/src/compiler/glsl/glcpp/tests/030-define-chain-obj-to-func-compose.c.expected b/src/compiler/glsl/glcpp/tests/030-define-chain-obj-to-func-compose.c.expected
new file mode 100644
index 00000000000..bed826e7831
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/030-define-chain-obj-to-func-compose.c.expected
@@ -0,0 +1,4 @@
+
+
+
+success
diff --git a/src/compiler/glsl/glcpp/tests/031-define-chain-func-to-func-compose.c b/src/compiler/glsl/glcpp/tests/031-define-chain-func-to-func-compose.c
new file mode 100644
index 00000000000..3f4c8744dff
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/031-define-chain-func-to-func-compose.c
@@ -0,0 +1,4 @@
+#define baz(failure) failure
+#define bar(failure) failure
+#define foo() bar(baz(success))
+foo()
diff --git a/src/compiler/glsl/glcpp/tests/031-define-chain-func-to-func-compose.c.expected b/src/compiler/glsl/glcpp/tests/031-define-chain-func-to-func-compose.c.expected
new file mode 100644
index 00000000000..bed826e7831
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/031-define-chain-func-to-func-compose.c.expected
@@ -0,0 +1,4 @@
+
+
+
+success
diff --git a/src/compiler/glsl/glcpp/tests/032-define-func-self-recurse.c b/src/compiler/glsl/glcpp/tests/032-define-func-self-recurse.c
new file mode 100644
index 00000000000..b3ac70f499c
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/032-define-func-self-recurse.c
@@ -0,0 +1,2 @@
+#define foo(a) foo(2*(a))
+foo(3)
diff --git a/src/compiler/glsl/glcpp/tests/032-define-func-self-recurse.c.expected b/src/compiler/glsl/glcpp/tests/032-define-func-self-recurse.c.expected
new file mode 100644
index 00000000000..983f9417401
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/032-define-func-self-recurse.c.expected
@@ -0,0 +1,2 @@
+
+foo(2*(3))
diff --git a/src/compiler/glsl/glcpp/tests/033-define-func-self-compose.c b/src/compiler/glsl/glcpp/tests/033-define-func-self-compose.c
new file mode 100644
index 00000000000..f65e48286cf
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/033-define-func-self-compose.c
@@ -0,0 +1,2 @@
+#define foo(a) foo(2*(a))
+foo(foo(3))
diff --git a/src/compiler/glsl/glcpp/tests/033-define-func-self-compose.c.expected b/src/compiler/glsl/glcpp/tests/033-define-func-self-compose.c.expected
new file mode 100644
index 00000000000..08183623643
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/033-define-func-self-compose.c.expected
@@ -0,0 +1,2 @@
+
+foo(2*(foo(2*(3))))
diff --git a/src/compiler/glsl/glcpp/tests/034-define-func-self-compose-non-func.c b/src/compiler/glsl/glcpp/tests/034-define-func-self-compose-non-func.c
new file mode 100644
index 00000000000..209a5f7e07c
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/034-define-func-self-compose-non-func.c
@@ -0,0 +1,2 @@
+#define foo(bar) bar
+foo(foo)
diff --git a/src/compiler/glsl/glcpp/tests/034-define-func-self-compose-non-func.c.expected b/src/compiler/glsl/glcpp/tests/034-define-func-self-compose-non-func.c.expected
new file mode 100644
index 00000000000..3f808fe665d
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/034-define-func-self-compose-non-func.c.expected
@@ -0,0 +1,2 @@
+
+foo
diff --git a/src/compiler/glsl/glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c b/src/compiler/glsl/glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c
new file mode 100644
index 00000000000..c307fbe830f
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c
@@ -0,0 +1,2 @@
+#define foo(bar) bar
+foo(1+foo)
diff --git a/src/compiler/glsl/glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c.expected b/src/compiler/glsl/glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c.expected
new file mode 100644
index 00000000000..09dfdd64e9b
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c.expected
@@ -0,0 +1,2 @@
+
+1+foo
diff --git a/src/compiler/glsl/glcpp/tests/036-define-func-non-macro-multi-token-argument.c b/src/compiler/glsl/glcpp/tests/036-define-func-non-macro-multi-token-argument.c
new file mode 100644
index 00000000000..b21ff336738
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/036-define-func-non-macro-multi-token-argument.c
@@ -0,0 +1,3 @@
+#define bar success
+#define foo(x) x
+foo(more bar)
diff --git a/src/compiler/glsl/glcpp/tests/036-define-func-non-macro-multi-token-argument.c.expected b/src/compiler/glsl/glcpp/tests/036-define-func-non-macro-multi-token-argument.c.expected
new file mode 100644
index 00000000000..580ed9599c5
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/036-define-func-non-macro-multi-token-argument.c.expected
@@ -0,0 +1,3 @@
+
+
+more success
diff --git a/src/compiler/glsl/glcpp/tests/037-finalize-unexpanded-macro.c b/src/compiler/glsl/glcpp/tests/037-finalize-unexpanded-macro.c
new file mode 100644
index 00000000000..b3a2f37f1b9
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/037-finalize-unexpanded-macro.c
@@ -0,0 +1,3 @@
+#define expand(x) expand(x once)
+#define foo(x) x
+foo(expand(just))
diff --git a/src/compiler/glsl/glcpp/tests/037-finalize-unexpanded-macro.c.expected b/src/compiler/glsl/glcpp/tests/037-finalize-unexpanded-macro.c.expected
new file mode 100644
index 00000000000..e804d7e4f9f
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/037-finalize-unexpanded-macro.c.expected
@@ -0,0 +1,3 @@
+
+
+expand(just once)
diff --git a/src/compiler/glsl/glcpp/tests/038-func-arg-with-commas.c b/src/compiler/glsl/glcpp/tests/038-func-arg-with-commas.c
new file mode 100644
index 00000000000..1407c7d6e3c
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/038-func-arg-with-commas.c
@@ -0,0 +1,2 @@
+#define foo(x) success
+foo(argument (with,embedded , commas) -- tricky)
diff --git a/src/compiler/glsl/glcpp/tests/038-func-arg-with-commas.c.expected b/src/compiler/glsl/glcpp/tests/038-func-arg-with-commas.c.expected
new file mode 100644
index 00000000000..6544adb3a25
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/038-func-arg-with-commas.c.expected
@@ -0,0 +1,2 @@
+
+success
diff --git a/src/compiler/glsl/glcpp/tests/039-func-arg-obj-macro-with-comma.c b/src/compiler/glsl/glcpp/tests/039-func-arg-obj-macro-with-comma.c
new file mode 100644
index 00000000000..a7c053bb402
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/039-func-arg-obj-macro-with-comma.c
@@ -0,0 +1,24 @@
+/* This works. */
+#define foo(a) (a)
+#define bar two,words
+foo(bar)
+
+/* So does this. */
+#define foo2(a,b) (a separate b)
+#define foo2_wrap(a) foo2(a)
+foo2_wrap(bar)
+
+/* But this generates an error. */
+#define foo_wrap(a) foo(a)
+foo_wrap(bar)
+
+/* Adding parentheses to foo_wrap fixes it. */
+#define foo_wrap_parens(a) foo((a))
+foo_wrap_parens(bar)
+
+/* As does adding parentheses to bar */
+#define bar_parens (two,words)
+foo_wrap(bar_parens)
+foo_wrap_parens(bar_parens)
+
+
diff --git a/src/compiler/glsl/glcpp/tests/039-func-arg-obj-macro-with-comma.c.expected b/src/compiler/glsl/glcpp/tests/039-func-arg-obj-macro-with-comma.c.expected
new file mode 100644
index 00000000000..4cc795338b2
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/039-func-arg-obj-macro-with-comma.c.expected
@@ -0,0 +1,26 @@
+0:12(21): preprocessor error: Error: macro foo invoked with 2 arguments (expected 1)
+
+
+
+
+(two,words)
+
+
+
+
+(two separate words)
+
+
+
+foo(two,words)
+
+
+
+((two,words))
+
+
+
+((two,words))
+(((two,words)))
+
+
diff --git a/src/compiler/glsl/glcpp/tests/040-token-pasting.c b/src/compiler/glsl/glcpp/tests/040-token-pasting.c
new file mode 100644
index 00000000000..caab3ba7368
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/040-token-pasting.c
@@ -0,0 +1,2 @@
+#define paste(a,b) a ## b
+paste(one , token)
diff --git a/src/compiler/glsl/glcpp/tests/040-token-pasting.c.expected b/src/compiler/glsl/glcpp/tests/040-token-pasting.c.expected
new file mode 100644
index 00000000000..48e836ec3fa
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/040-token-pasting.c.expected
@@ -0,0 +1,2 @@
+
+onetoken
diff --git a/src/compiler/glsl/glcpp/tests/041-if-0.c b/src/compiler/glsl/glcpp/tests/041-if-0.c
new file mode 100644
index 00000000000..2cab677d3e8
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/041-if-0.c
@@ -0,0 +1,5 @@
+success_1
+#if 0
+failure
+#endif
+success_2
diff --git a/src/compiler/glsl/glcpp/tests/041-if-0.c.expected b/src/compiler/glsl/glcpp/tests/041-if-0.c.expected
new file mode 100644
index 00000000000..8b506b32d55
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/041-if-0.c.expected
@@ -0,0 +1,5 @@
+success_1
+
+
+
+success_2
diff --git a/src/compiler/glsl/glcpp/tests/042-if-1.c b/src/compiler/glsl/glcpp/tests/042-if-1.c
new file mode 100644
index 00000000000..874a25cf41b
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/042-if-1.c
@@ -0,0 +1,5 @@
+success_1
+#if 1
+success_2
+#endif
+success_3
diff --git a/src/compiler/glsl/glcpp/tests/042-if-1.c.expected b/src/compiler/glsl/glcpp/tests/042-if-1.c.expected
new file mode 100644
index 00000000000..a6ae9465a97
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/042-if-1.c.expected
@@ -0,0 +1,5 @@
+success_1
+
+success_2
+
+success_3
diff --git a/src/compiler/glsl/glcpp/tests/043-if-0-else.c b/src/compiler/glsl/glcpp/tests/043-if-0-else.c
new file mode 100644
index 00000000000..323351f9dbf
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/043-if-0-else.c
@@ -0,0 +1,7 @@
+success_1
+#if 0
+failure
+#else
+success_2
+#endif
+success_3
diff --git a/src/compiler/glsl/glcpp/tests/043-if-0-else.c.expected b/src/compiler/glsl/glcpp/tests/043-if-0-else.c.expected
new file mode 100644
index 00000000000..3d7e6be96c8
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/043-if-0-else.c.expected
@@ -0,0 +1,7 @@
+success_1
+
+
+
+success_2
+
+success_3
diff --git a/src/compiler/glsl/glcpp/tests/044-if-1-else.c b/src/compiler/glsl/glcpp/tests/044-if-1-else.c
new file mode 100644
index 00000000000..28dfc25c6f0
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/044-if-1-else.c
@@ -0,0 +1,7 @@
+success_1
+#if 1
+success_2
+#else
+failure
+#endif
+success_3
diff --git a/src/compiler/glsl/glcpp/tests/044-if-1-else.c.expected b/src/compiler/glsl/glcpp/tests/044-if-1-else.c.expected
new file mode 100644
index 00000000000..4a31e1cfa9e
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/044-if-1-else.c.expected
@@ -0,0 +1,7 @@
+success_1
+
+success_2
+
+
+
+success_3
diff --git a/src/compiler/glsl/glcpp/tests/045-if-0-elif.c b/src/compiler/glsl/glcpp/tests/045-if-0-elif.c
new file mode 100644
index 00000000000..e50f686d461
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/045-if-0-elif.c
@@ -0,0 +1,11 @@
+success_1
+#if 0
+failure_1
+#elif 0
+failure_2
+#elif 1
+success_3
+#elif 1
+failure_3
+#endif
+success_4
diff --git a/src/compiler/glsl/glcpp/tests/045-if-0-elif.c.expected b/src/compiler/glsl/glcpp/tests/045-if-0-elif.c.expected
new file mode 100644
index 00000000000..a9bb1588e4f
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/045-if-0-elif.c.expected
@@ -0,0 +1,11 @@
+success_1
+
+
+
+
+
+success_3
+
+
+
+success_4
diff --git a/src/compiler/glsl/glcpp/tests/046-if-1-elsif.c b/src/compiler/glsl/glcpp/tests/046-if-1-elsif.c
new file mode 100644
index 00000000000..130515a01ea
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/046-if-1-elsif.c
@@ -0,0 +1,11 @@
+success_1
+#if 1
+success_2
+#elif 0
+failure_1
+#elif 1
+failure_2
+#elif 0
+failure_3
+#endif
+success_3
diff --git a/src/compiler/glsl/glcpp/tests/046-if-1-elsif.c.expected b/src/compiler/glsl/glcpp/tests/046-if-1-elsif.c.expected
new file mode 100644
index 00000000000..a4995713ca5
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/046-if-1-elsif.c.expected
@@ -0,0 +1,11 @@
+success_1
+
+success_2
+
+
+
+
+
+
+
+success_3
diff --git a/src/compiler/glsl/glcpp/tests/047-if-elif-else.c b/src/compiler/glsl/glcpp/tests/047-if-elif-else.c
new file mode 100644
index 00000000000..e8f0838a9ed
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/047-if-elif-else.c
@@ -0,0 +1,11 @@
+success_1
+#if 0
+failure_1
+#elif 0
+failure_2
+#elif 0
+failure_3
+#else
+success_2
+#endif
+success_3
diff --git a/src/compiler/glsl/glcpp/tests/047-if-elif-else.c.expected b/src/compiler/glsl/glcpp/tests/047-if-elif-else.c.expected
new file mode 100644
index 00000000000..54d30861197
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/047-if-elif-else.c.expected
@@ -0,0 +1,11 @@
+success_1
+
+
+
+
+
+
+
+success_2
+
+success_3
diff --git a/src/compiler/glsl/glcpp/tests/048-if-nested.c b/src/compiler/glsl/glcpp/tests/048-if-nested.c
new file mode 100644
index 00000000000..fc4679c3be4
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/048-if-nested.c
@@ -0,0 +1,11 @@
+success_1
+#if 0
+failure_1
+#if 1
+failure_2
+#else
+failure_3
+#endif
+failure_4
+#endif
+success_2
diff --git a/src/compiler/glsl/glcpp/tests/048-if-nested.c.expected b/src/compiler/glsl/glcpp/tests/048-if-nested.c.expected
new file mode 100644
index 00000000000..8beb9c32c37
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/048-if-nested.c.expected
@@ -0,0 +1,11 @@
+success_1
+
+
+
+
+
+
+
+
+
+success_2
diff --git a/src/compiler/glsl/glcpp/tests/049-if-expression-precedence.c b/src/compiler/glsl/glcpp/tests/049-if-expression-precedence.c
new file mode 100644
index 00000000000..833ea03882a
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/049-if-expression-precedence.c
@@ -0,0 +1,5 @@
+#if 1 + 2 * 3 + - (25 % 17 - + 1)
+failure with operator precedence
+#else
+success
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/049-if-expression-precedence.c.expected b/src/compiler/glsl/glcpp/tests/049-if-expression-precedence.c.expected
new file mode 100644
index 00000000000..729bdd15f80
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/049-if-expression-precedence.c.expected
@@ -0,0 +1,5 @@
+
+
+
+success
+
diff --git a/src/compiler/glsl/glcpp/tests/050-if-defined.c b/src/compiler/glsl/glcpp/tests/050-if-defined.c
new file mode 100644
index 00000000000..34f0f95140e
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/050-if-defined.c
@@ -0,0 +1,17 @@
+#if defined foo
+failure_1
+#else
+success_1
+#endif
+#define foo
+#if defined foo
+success_2
+#else
+failure_2
+#endif
+#undef foo
+#if defined foo
+failure_3
+#else
+success_3
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/050-if-defined.c.expected b/src/compiler/glsl/glcpp/tests/050-if-defined.c.expected
new file mode 100644
index 00000000000..737eb8d9403
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/050-if-defined.c.expected
@@ -0,0 +1,17 @@
+
+
+
+success_1
+
+
+
+success_2
+
+
+
+
+
+
+
+success_3
+
diff --git a/src/compiler/glsl/glcpp/tests/051-if-relational.c b/src/compiler/glsl/glcpp/tests/051-if-relational.c
new file mode 100644
index 00000000000..c3db488e0de
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/051-if-relational.c
@@ -0,0 +1,35 @@
+#if 3 < 2
+failure_1
+#else
+success_1
+#endif
+
+#if 3 >= 2
+success_2
+#else
+failure_2
+#endif
+
+#if 2 + 3 <= 5
+success_3
+#else
+failure_3
+#endif
+
+#if 3 - 2 == 1
+success_3
+#else
+failure_3
+#endif
+
+#if 1 > 3
+failure_4
+#else
+success_4
+#endif
+
+#if 1 != 5
+success_5
+#else
+failure_5
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/051-if-relational.c.expected b/src/compiler/glsl/glcpp/tests/051-if-relational.c.expected
new file mode 100644
index 00000000000..652fefdd43b
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/051-if-relational.c.expected
@@ -0,0 +1,35 @@
+
+
+
+success_1
+
+
+
+success_2
+
+
+
+
+
+success_3
+
+
+
+
+
+success_3
+
+
+
+
+
+
+
+success_4
+
+
+
+success_5
+
+
+
diff --git a/src/compiler/glsl/glcpp/tests/052-if-bitwise.c b/src/compiler/glsl/glcpp/tests/052-if-bitwise.c
new file mode 100644
index 00000000000..2d8e45eb61e
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/052-if-bitwise.c
@@ -0,0 +1,20 @@
+#if (0xaaaaaaaa | 0x55555555) != 4294967295
+failure_1
+#else
+success_1
+#endif
+#if (0x12345678 ^ 0xfdecba98) == 4023971040
+success_2
+#else
+failure_2
+#endif
+#if (~ 0xdeadbeef) != -3735928560
+failure_3
+#else
+success_3
+#endif
+#if (0667 & 0733) == 403
+success_4
+#else
+failure_4
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/052-if-bitwise.c.expected b/src/compiler/glsl/glcpp/tests/052-if-bitwise.c.expected
new file mode 100644
index 00000000000..44e52b206e5
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/052-if-bitwise.c.expected
@@ -0,0 +1,20 @@
+
+
+
+success_1
+
+
+success_2
+
+
+
+
+
+
+success_3
+
+
+success_4
+
+
+
diff --git a/src/compiler/glsl/glcpp/tests/053-if-divide-and-shift.c b/src/compiler/glsl/glcpp/tests/053-if-divide-and-shift.c
new file mode 100644
index 00000000000..d24c54a88d1
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/053-if-divide-and-shift.c
@@ -0,0 +1,15 @@
+#if (15 / 2) != 7
+failure_1
+#else
+success_1
+#endif
+#if (1 << 12) == 4096
+success_2
+#else
+failure_2
+#endif
+#if (31762 >> 8) != 124
+failure_3
+#else
+success_3
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/053-if-divide-and-shift.c.expected b/src/compiler/glsl/glcpp/tests/053-if-divide-and-shift.c.expected
new file mode 100644
index 00000000000..7e78e0454e0
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/053-if-divide-and-shift.c.expected
@@ -0,0 +1,15 @@
+
+
+
+success_1
+
+
+success_2
+
+
+
+
+
+
+success_3
+
diff --git a/src/compiler/glsl/glcpp/tests/054-if-with-macros.c b/src/compiler/glsl/glcpp/tests/054-if-with-macros.c
new file mode 100644
index 00000000000..3da79a0d96e
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/054-if-with-macros.c
@@ -0,0 +1,34 @@
+#define one 1
+#define two 2
+#define three 3
+#define five 5
+#if five < two
+failure_1
+#else
+success_1
+#endif
+#if three >= two
+success_2
+#else
+failure_2
+#endif
+#if two + three <= five
+success_3
+#else
+failure_3
+#endif
+#if five - two == three
+success_4
+#else
+failure_4
+#endif
+#if one > three
+failure_5
+#else
+success_5
+#endif
+#if one != five
+success_6
+#else
+failure_6
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/054-if-with-macros.c.expected b/src/compiler/glsl/glcpp/tests/054-if-with-macros.c.expected
new file mode 100644
index 00000000000..70f737c90a9
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/054-if-with-macros.c.expected
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+success_1
+
+
+success_2
+
+
+
+
+success_3
+
+
+
+
+success_4
+
+
+
+
+
+
+success_5
+
+
+success_6
+
+
+
diff --git a/src/compiler/glsl/glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c b/src/compiler/glsl/glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c
new file mode 100644
index 00000000000..00f2c2346d6
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c
@@ -0,0 +1,3 @@
+#define failure() success
+#define foo failure
+foo()
diff --git a/src/compiler/glsl/glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c.expected b/src/compiler/glsl/glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c.expected
new file mode 100644
index 00000000000..94c15f95059
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c.expected
@@ -0,0 +1,3 @@
+
+
+success
diff --git a/src/compiler/glsl/glcpp/tests/056-macro-argument-with-comma.c b/src/compiler/glsl/glcpp/tests/056-macro-argument-with-comma.c
new file mode 100644
index 00000000000..58701d1f25b
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/056-macro-argument-with-comma.c
@@ -0,0 +1,4 @@
+#define bar with,embedded,commas
+#define function(x) success
+#define foo function
+foo(bar)
diff --git a/src/compiler/glsl/glcpp/tests/056-macro-argument-with-comma.c.expected b/src/compiler/glsl/glcpp/tests/056-macro-argument-with-comma.c.expected
new file mode 100644
index 00000000000..bed826e7831
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/056-macro-argument-with-comma.c.expected
@@ -0,0 +1,4 @@
+
+
+
+success
diff --git a/src/compiler/glsl/glcpp/tests/057-empty-arguments.c b/src/compiler/glsl/glcpp/tests/057-empty-arguments.c
new file mode 100644
index 00000000000..6140232865d
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/057-empty-arguments.c
@@ -0,0 +1,6 @@
+#define zero() success
+zero()
+#define one(x) success
+one()
+#define two(x,y) success
+two(,)
diff --git a/src/compiler/glsl/glcpp/tests/057-empty-arguments.c.expected b/src/compiler/glsl/glcpp/tests/057-empty-arguments.c.expected
new file mode 100644
index 00000000000..7d97e15e29d
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/057-empty-arguments.c.expected
@@ -0,0 +1,6 @@
+
+success
+
+success
+
+success
diff --git a/src/compiler/glsl/glcpp/tests/058-token-pasting-empty-arguments.c b/src/compiler/glsl/glcpp/tests/058-token-pasting-empty-arguments.c
new file mode 100644
index 00000000000..8ac260c76b6
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/058-token-pasting-empty-arguments.c
@@ -0,0 +1,5 @@
+#define paste(x,y) x ## y
+paste(a,b)
+paste(a,)
+paste(,b)
+paste(,)
diff --git a/src/compiler/glsl/glcpp/tests/058-token-pasting-empty-arguments.c.expected b/src/compiler/glsl/glcpp/tests/058-token-pasting-empty-arguments.c.expected
new file mode 100644
index 00000000000..e0967a1b951
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/058-token-pasting-empty-arguments.c.expected
@@ -0,0 +1,5 @@
+
+ab
+a
+b
+
diff --git a/src/compiler/glsl/glcpp/tests/059-token-pasting-integer.c b/src/compiler/glsl/glcpp/tests/059-token-pasting-integer.c
new file mode 100644
index 00000000000..37b895a4237
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/059-token-pasting-integer.c
@@ -0,0 +1,4 @@
+#define paste(x,y) x ## y
+paste(1,2)
+paste(1,000)
+paste(identifier,2)
diff --git a/src/compiler/glsl/glcpp/tests/059-token-pasting-integer.c.expected b/src/compiler/glsl/glcpp/tests/059-token-pasting-integer.c.expected
new file mode 100644
index 00000000000..f1288aa7cb7
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/059-token-pasting-integer.c.expected
@@ -0,0 +1,4 @@
+
+12
+1000
+identifier2
diff --git a/src/compiler/glsl/glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c b/src/compiler/glsl/glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c
new file mode 100644
index 00000000000..ed80ea879ce
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c
@@ -0,0 +1,3 @@
+#define double(a) a*2
+#define foo double(
+foo 5)
diff --git a/src/compiler/glsl/glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c.expected b/src/compiler/glsl/glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c.expected
new file mode 100644
index 00000000000..3e5501aa6e8
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c.expected
@@ -0,0 +1,3 @@
+
+
+5*2
diff --git a/src/compiler/glsl/glcpp/tests/061-define-chain-obj-to-func-multi.c b/src/compiler/glsl/glcpp/tests/061-define-chain-obj-to-func-multi.c
new file mode 100644
index 00000000000..6dbfd1f62d1
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/061-define-chain-obj-to-func-multi.c
@@ -0,0 +1,5 @@
+#define foo(x) success
+#define bar foo
+#define baz bar
+#define joe baz
+joe (failure)
diff --git a/src/compiler/glsl/glcpp/tests/061-define-chain-obj-to-func-multi.c.expected b/src/compiler/glsl/glcpp/tests/061-define-chain-obj-to-func-multi.c.expected
new file mode 100644
index 00000000000..15eb64b97f1
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/061-define-chain-obj-to-func-multi.c.expected
@@ -0,0 +1,5 @@
+
+
+
+
+success
diff --git a/src/compiler/glsl/glcpp/tests/062-if-0-skips-garbage.c b/src/compiler/glsl/glcpp/tests/062-if-0-skips-garbage.c
new file mode 100644
index 00000000000..d9e439bb890
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/062-if-0-skips-garbage.c
@@ -0,0 +1,5 @@
+#define foo(a,b)
+#if 0
+foo(bar)
+foo(
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/062-if-0-skips-garbage.c.expected b/src/compiler/glsl/glcpp/tests/062-if-0-skips-garbage.c.expected
new file mode 100644
index 00000000000..3f2ff2d6cc8
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/062-if-0-skips-garbage.c.expected
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/compiler/glsl/glcpp/tests/063-comments.c b/src/compiler/glsl/glcpp/tests/063-comments.c
new file mode 100644
index 00000000000..e641d2f0f9e
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/063-comments.c
@@ -0,0 +1,20 @@
+/* this is a comment */
+// so is this
+// */
+f = g/**//h;
+/*//*/l();
+m = n//**/o
++ p;
+/* this
+comment spans
+multiple lines and
+contains *** stars
+and slashes / *** /
+and other stuff.
+****/
+more code here
+/* Test that /* nested
+ comments */
+are not treated like comments.
+/*/ this is a comment */
+/*/*/
diff --git a/src/compiler/glsl/glcpp/tests/063-comments.c.expected b/src/compiler/glsl/glcpp/tests/063-comments.c.expected
new file mode 100644
index 00000000000..f6e10ce0377
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/063-comments.c.expected
@@ -0,0 +1,20 @@
+
+
+
+f = g /h;
+ l();
+m = n
++ p;
+
+
+
+
+
+
+
+more code here
+
+
+are not treated like comments.
+
+
diff --git a/src/compiler/glsl/glcpp/tests/064-version.c b/src/compiler/glsl/glcpp/tests/064-version.c
new file mode 100644
index 00000000000..21326481b87
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/064-version.c
@@ -0,0 +1,2 @@
+#version 130
+#define FOO
diff --git a/src/compiler/glsl/glcpp/tests/064-version.c.expected b/src/compiler/glsl/glcpp/tests/064-version.c.expected
new file mode 100644
index 00000000000..4036b1ee374
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/064-version.c.expected
@@ -0,0 +1,2 @@
+#version 130
+
diff --git a/src/compiler/glsl/glcpp/tests/065-if-defined-parens.c b/src/compiler/glsl/glcpp/tests/065-if-defined-parens.c
new file mode 100644
index 00000000000..48aa0f8c3ef
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/065-if-defined-parens.c
@@ -0,0 +1,17 @@
+#if defined(foo)
+failure_1
+#else
+success_1
+#endif
+#define foo
+#if defined ( foo )
+success_2
+#else
+failure_2
+#endif
+#undef foo
+#if defined (foo)
+failure_3
+#else
+success_3
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/065-if-defined-parens.c.expected b/src/compiler/glsl/glcpp/tests/065-if-defined-parens.c.expected
new file mode 100644
index 00000000000..737eb8d9403
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/065-if-defined-parens.c.expected
@@ -0,0 +1,17 @@
+
+
+
+success_1
+
+
+
+success_2
+
+
+
+
+
+
+
+success_3
+
diff --git a/src/compiler/glsl/glcpp/tests/066-if-nospace-expression.c b/src/compiler/glsl/glcpp/tests/066-if-nospace-expression.c
new file mode 100644
index 00000000000..3b0b47349d0
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/066-if-nospace-expression.c
@@ -0,0 +1,3 @@
+#if(1)
+success
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/066-if-nospace-expression.c.expected b/src/compiler/glsl/glcpp/tests/066-if-nospace-expression.c.expected
new file mode 100644
index 00000000000..5a28fb3b66c
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/066-if-nospace-expression.c.expected
@@ -0,0 +1,3 @@
+
+success
+
diff --git a/src/compiler/glsl/glcpp/tests/067-nested-ifdef-ifndef.c b/src/compiler/glsl/glcpp/tests/067-nested-ifdef-ifndef.c
new file mode 100644
index 00000000000..f46cce4e60a
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/067-nested-ifdef-ifndef.c
@@ -0,0 +1,40 @@
+#define D1
+#define D2
+
+#define result success
+
+#ifdef U1
+#ifdef U2
+#undef result
+#define result failure
+#endif
+#endif
+result
+
+#ifndef D1
+#ifndef D2
+#undef result
+#define result failure
+#endif
+#endif
+result
+
+#undef result
+#define result failure
+#ifdef D1
+#ifdef D2
+#undef result
+#define result success
+#endif
+#endif
+result
+
+#undef result
+#define result failure
+#ifndef U1
+#ifndef U2
+#undef result
+#define result success
+#endif
+#endif
+result
diff --git a/src/compiler/glsl/glcpp/tests/067-nested-ifdef-ifndef.c.expected b/src/compiler/glsl/glcpp/tests/067-nested-ifdef-ifndef.c.expected
new file mode 100644
index 00000000000..9a5ed2eb2d3
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/067-nested-ifdef-ifndef.c.expected
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+success
+
+
+
+
+
+
+
+success
+
+
+
+
+
+
+
+
+
+success
+
+
+
+
+
+
+
+
+
+success
diff --git a/src/compiler/glsl/glcpp/tests/068-accidental-pasting.c b/src/compiler/glsl/glcpp/tests/068-accidental-pasting.c
new file mode 100644
index 00000000000..699ac5144e5
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/068-accidental-pasting.c
@@ -0,0 +1,11 @@
+#define empty
+<empty<
+<empty=
+>empty>
+>empty=
+=empty=
+!empty=
+&empty&
+|empty|
++empty+
+-empty-
diff --git a/src/compiler/glsl/glcpp/tests/068-accidental-pasting.c.expected b/src/compiler/glsl/glcpp/tests/068-accidental-pasting.c.expected
new file mode 100644
index 00000000000..27582cda5e8
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/068-accidental-pasting.c.expected
@@ -0,0 +1,11 @@
+
+< <
+< =
+> >
+> =
+= =
+! =
+& &
+| |
++ +
+- -
diff --git a/src/compiler/glsl/glcpp/tests/069-repeated-argument.c b/src/compiler/glsl/glcpp/tests/069-repeated-argument.c
new file mode 100644
index 00000000000..2b46ead294c
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/069-repeated-argument.c
@@ -0,0 +1,2 @@
+#define double(x) x x
+double(1)
diff --git a/src/compiler/glsl/glcpp/tests/069-repeated-argument.c.expected b/src/compiler/glsl/glcpp/tests/069-repeated-argument.c.expected
new file mode 100644
index 00000000000..8b4b095e488
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/069-repeated-argument.c.expected
@@ -0,0 +1,2 @@
+
+1 1
diff --git a/src/compiler/glsl/glcpp/tests/070-undefined-macro-in-expression.c b/src/compiler/glsl/glcpp/tests/070-undefined-macro-in-expression.c
new file mode 100644
index 00000000000..d15a4840b01
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/070-undefined-macro-in-expression.c
@@ -0,0 +1,5 @@
+#if UNDEFINED_MACRO
+Failure
+#else
+Success
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/070-undefined-macro-in-expression.c.expected b/src/compiler/glsl/glcpp/tests/070-undefined-macro-in-expression.c.expected
new file mode 100644
index 00000000000..44b93a434fa
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/070-undefined-macro-in-expression.c.expected
@@ -0,0 +1,5 @@
+
+
+
+Success
+
diff --git a/src/compiler/glsl/glcpp/tests/071-punctuator.c b/src/compiler/glsl/glcpp/tests/071-punctuator.c
new file mode 100644
index 00000000000..959d6825988
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/071-punctuator.c
@@ -0,0 +1 @@
+a = b
diff --git a/src/compiler/glsl/glcpp/tests/071-punctuator.c.expected b/src/compiler/glsl/glcpp/tests/071-punctuator.c.expected
new file mode 100644
index 00000000000..959d6825988
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/071-punctuator.c.expected
@@ -0,0 +1 @@
+a = b
diff --git a/src/compiler/glsl/glcpp/tests/072-token-pasting-same-line.c b/src/compiler/glsl/glcpp/tests/072-token-pasting-same-line.c
new file mode 100644
index 00000000000..e421e9d5e29
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/072-token-pasting-same-line.c
@@ -0,0 +1,2 @@
+#define paste(x) success_ ## x
+paste(1) paste(2) paste(3)
diff --git a/src/compiler/glsl/glcpp/tests/072-token-pasting-same-line.c.expected b/src/compiler/glsl/glcpp/tests/072-token-pasting-same-line.c.expected
new file mode 100644
index 00000000000..7b80af7e465
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/072-token-pasting-same-line.c.expected
@@ -0,0 +1,2 @@
+
+success_1 success_2 success_3
diff --git a/src/compiler/glsl/glcpp/tests/073-if-in-ifdef.c b/src/compiler/glsl/glcpp/tests/073-if-in-ifdef.c
new file mode 100644
index 00000000000..61a48097ca3
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/073-if-in-ifdef.c
@@ -0,0 +1,4 @@
+#ifdef UNDEF
+#if UNDEF > 1
+#endif
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/073-if-in-ifdef.c.expected b/src/compiler/glsl/glcpp/tests/073-if-in-ifdef.c.expected
new file mode 100644
index 00000000000..fd40910d9e7
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/073-if-in-ifdef.c.expected
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/compiler/glsl/glcpp/tests/074-elif-undef.c b/src/compiler/glsl/glcpp/tests/074-elif-undef.c
new file mode 100644
index 00000000000..67aac8977e0
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/074-elif-undef.c
@@ -0,0 +1,3 @@
+#ifndef UNDEF
+#elif UNDEF < 0
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/074-elif-undef.c.expected b/src/compiler/glsl/glcpp/tests/074-elif-undef.c.expected
new file mode 100644
index 00000000000..b28b04f6431
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/074-elif-undef.c.expected
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/compiler/glsl/glcpp/tests/075-elif-elif-undef.c b/src/compiler/glsl/glcpp/tests/075-elif-elif-undef.c
new file mode 100644
index 00000000000..264bc4f10ee
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/075-elif-elif-undef.c
@@ -0,0 +1,4 @@
+#ifndef UNDEF
+#elif UNDEF < 0
+#elif UNDEF == 3
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/075-elif-elif-undef.c.expected b/src/compiler/glsl/glcpp/tests/075-elif-elif-undef.c.expected
new file mode 100644
index 00000000000..fd40910d9e7
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/075-elif-elif-undef.c.expected
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/compiler/glsl/glcpp/tests/076-elif-undef-nested.c b/src/compiler/glsl/glcpp/tests/076-elif-undef-nested.c
new file mode 100644
index 00000000000..ebd550ed005
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/076-elif-undef-nested.c
@@ -0,0 +1,5 @@
+#ifdef UNDEF
+#if UNDEF == 4
+#elif UNDEF == 5
+#endif
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/076-elif-undef-nested.c.expected b/src/compiler/glsl/glcpp/tests/076-elif-undef-nested.c.expected
new file mode 100644
index 00000000000..3f2ff2d6cc8
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/076-elif-undef-nested.c.expected
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/compiler/glsl/glcpp/tests/077-else-without-if.c b/src/compiler/glsl/glcpp/tests/077-else-without-if.c
new file mode 100644
index 00000000000..81f00bfe278
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/077-else-without-if.c
@@ -0,0 +1 @@
+#else
diff --git a/src/compiler/glsl/glcpp/tests/077-else-without-if.c.expected b/src/compiler/glsl/glcpp/tests/077-else-without-if.c.expected
new file mode 100644
index 00000000000..69f34047033
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/077-else-without-if.c.expected
@@ -0,0 +1,3 @@
+0:1(1): preprocessor error: #else without #if
+
+
diff --git a/src/compiler/glsl/glcpp/tests/078-elif-without-if.c b/src/compiler/glsl/glcpp/tests/078-elif-without-if.c
new file mode 100644
index 00000000000..60466b3890a
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/078-elif-without-if.c
@@ -0,0 +1 @@
+#elif defined FOO
diff --git a/src/compiler/glsl/glcpp/tests/078-elif-without-if.c.expected b/src/compiler/glsl/glcpp/tests/078-elif-without-if.c.expected
new file mode 100644
index 00000000000..b8e40ecc09b
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/078-elif-without-if.c.expected
@@ -0,0 +1,3 @@
+0:1(1): preprocessor error: #elif without #if
+
+
diff --git a/src/compiler/glsl/glcpp/tests/079-endif-without-if.c b/src/compiler/glsl/glcpp/tests/079-endif-without-if.c
new file mode 100644
index 00000000000..69331c3ca9d
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/079-endif-without-if.c
@@ -0,0 +1 @@
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/079-endif-without-if.c.expected b/src/compiler/glsl/glcpp/tests/079-endif-without-if.c.expected
new file mode 100644
index 00000000000..7ae579dd25e
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/079-endif-without-if.c.expected
@@ -0,0 +1,3 @@
+0:1(1): preprocessor error: #endif without #if
+
+
diff --git a/src/compiler/glsl/glcpp/tests/080-if-without-expression.c b/src/compiler/glsl/glcpp/tests/080-if-without-expression.c
new file mode 100644
index 00000000000..a27ba36a366
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/080-if-without-expression.c
@@ -0,0 +1,4 @@
+/* Error message for unskipped #if with no expression. */
+#if
+#endif
+
diff --git a/src/compiler/glsl/glcpp/tests/080-if-without-expression.c.expected b/src/compiler/glsl/glcpp/tests/080-if-without-expression.c.expected
new file mode 100644
index 00000000000..2e4cd7323c5
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/080-if-without-expression.c.expected
@@ -0,0 +1,5 @@
+0:2(1): preprocessor error: #if with no expression
+
+
+
+
diff --git a/src/compiler/glsl/glcpp/tests/081-elif-without-expression.c b/src/compiler/glsl/glcpp/tests/081-elif-without-expression.c
new file mode 100644
index 00000000000..79c78663dd3
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/081-elif-without-expression.c
@@ -0,0 +1,3 @@
+#if 0
+#elif
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/081-elif-without-expression.c.expected b/src/compiler/glsl/glcpp/tests/081-elif-without-expression.c.expected
new file mode 100644
index 00000000000..b607b849068
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/081-elif-without-expression.c.expected
@@ -0,0 +1,4 @@
+0:2(1): preprocessor error: #elif with no expression
+
+
+
diff --git a/src/compiler/glsl/glcpp/tests/082-invalid-paste.c b/src/compiler/glsl/glcpp/tests/082-invalid-paste.c
new file mode 100644
index 00000000000..8b84d50c3a0
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/082-invalid-paste.c
@@ -0,0 +1,7 @@
+#define PASTE(x,y) x ## y
+PASTE(<,>)
+PASTE(0,abc)
+PASTE(1,=)
+PASTE(2,@)
+PASTE(3,-4)
+PASTE(4,+5.2)
diff --git a/src/compiler/glsl/glcpp/tests/082-invalid-paste.c.expected b/src/compiler/glsl/glcpp/tests/082-invalid-paste.c.expected
new file mode 100644
index 00000000000..b48a2d6d296
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/082-invalid-paste.c.expected
@@ -0,0 +1,19 @@
+0:2(7): preprocessor error:
+Pasting "<" and ">" does not give a valid preprocessing token.
+0:3(7): preprocessor error:
+Pasting "0" and "abc" does not give a valid preprocessing token.
+0:4(7): preprocessor error:
+Pasting "1" and "=" does not give a valid preprocessing token.
+0:5(7): preprocessor error:
+Pasting "2" and "@" does not give a valid preprocessing token.
+0:6(7): preprocessor error:
+Pasting "3" and "-" does not give a valid preprocessing token.
+0:7(7): preprocessor error:
+Pasting "4" and "+" does not give a valid preprocessing token.
+
+<
+0
+1
+2
+34
+45.2
diff --git a/src/compiler/glsl/glcpp/tests/083-unterminated-if.c b/src/compiler/glsl/glcpp/tests/083-unterminated-if.c
new file mode 100644
index 00000000000..91806350927
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/083-unterminated-if.c
@@ -0,0 +1,2 @@
+#if 1
+
diff --git a/src/compiler/glsl/glcpp/tests/083-unterminated-if.c.expected b/src/compiler/glsl/glcpp/tests/083-unterminated-if.c.expected
new file mode 100644
index 00000000000..4659ab6fe67
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/083-unterminated-if.c.expected
@@ -0,0 +1,4 @@
+0:1(6): preprocessor error: Unterminated #if
+
+
+
diff --git a/src/compiler/glsl/glcpp/tests/084-unbalanced-parentheses.c b/src/compiler/glsl/glcpp/tests/084-unbalanced-parentheses.c
new file mode 100644
index 00000000000..0789ba5e525
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/084-unbalanced-parentheses.c
@@ -0,0 +1,2 @@
+#define FUNC(x) (2*(x))
+FUNC(23
diff --git a/src/compiler/glsl/glcpp/tests/084-unbalanced-parentheses.c.expected b/src/compiler/glsl/glcpp/tests/084-unbalanced-parentheses.c.expected
new file mode 100644
index 00000000000..af49a37369d
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/084-unbalanced-parentheses.c.expected
@@ -0,0 +1,2 @@
+0:2(8): preprocessor error: syntax error, unexpected $end
+
diff --git a/src/compiler/glsl/glcpp/tests/085-incorrect-argument-count.c b/src/compiler/glsl/glcpp/tests/085-incorrect-argument-count.c
new file mode 100644
index 00000000000..91bea600612
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/085-incorrect-argument-count.c
@@ -0,0 +1,5 @@
+#define MULT(x,y) ((x)*(y))
+MULT()
+MULT(1)
+MULT(1,2,3)
+
diff --git a/src/compiler/glsl/glcpp/tests/085-incorrect-argument-count.c.expected b/src/compiler/glsl/glcpp/tests/085-incorrect-argument-count.c.expected
new file mode 100644
index 00000000000..d23845bfd49
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/085-incorrect-argument-count.c.expected
@@ -0,0 +1,11 @@
+0:2(1): preprocessor error: Error: macro MULT invoked with 1 arguments (expected 2)
+
+0:3(1): preprocessor error: Error: macro MULT invoked with 1 arguments (expected 2)
+
+0:4(1): preprocessor error: Error: macro MULT invoked with 3 arguments (expected 2)
+
+
+MULT()
+MULT(1)
+MULT(1,2,3)
+
diff --git a/src/compiler/glsl/glcpp/tests/086-reserved-macro-names.c b/src/compiler/glsl/glcpp/tests/086-reserved-macro-names.c
new file mode 100644
index 00000000000..a6b7201f95d
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/086-reserved-macro-names.c
@@ -0,0 +1,3 @@
+#define __BAD reserved
+#define GL_ALSO_BAD() also reserved
+#define THIS__TOO__IS__BAD reserved
diff --git a/src/compiler/glsl/glcpp/tests/086-reserved-macro-names.c.expected b/src/compiler/glsl/glcpp/tests/086-reserved-macro-names.c.expected
new file mode 100644
index 00000000000..38b089daec3
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/086-reserved-macro-names.c.expected
@@ -0,0 +1,9 @@
+0:1(9): preprocessor warning: Macro names containing "__" are reserved for use by the implementation.
+
+0:2(9): preprocessor error: Macro names starting with "GL_" are reserved.
+
+0:3(9): preprocessor warning: Macro names containing "__" are reserved for use by the implementation.
+
+
+
+
diff --git a/src/compiler/glsl/glcpp/tests/087-if-comments.c b/src/compiler/glsl/glcpp/tests/087-if-comments.c
new file mode 100644
index 00000000000..ce8dc43057f
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/087-if-comments.c
@@ -0,0 +1,5 @@
+#if (1 == 0) // dangerous comment
+fail
+#else
+win
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/087-if-comments.c.expected b/src/compiler/glsl/glcpp/tests/087-if-comments.c.expected
new file mode 100644
index 00000000000..2783a9c14d5
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/087-if-comments.c.expected
@@ -0,0 +1,5 @@
+
+
+
+win
+
diff --git a/src/compiler/glsl/glcpp/tests/088-redefine-macro-legitimate.c b/src/compiler/glsl/glcpp/tests/088-redefine-macro-legitimate.c
new file mode 100644
index 00000000000..422c6546414
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/088-redefine-macro-legitimate.c
@@ -0,0 +1,5 @@
+#define abc 123
+#define abc 123
+
+#define foo(x) ( x ) + 23
+#define foo(x) ( x ) + 23
diff --git a/src/compiler/glsl/glcpp/tests/088-redefine-macro-legitimate.c.expected b/src/compiler/glsl/glcpp/tests/088-redefine-macro-legitimate.c.expected
new file mode 100644
index 00000000000..3f2ff2d6cc8
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/088-redefine-macro-legitimate.c.expected
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/compiler/glsl/glcpp/tests/089-redefine-macro-error.c b/src/compiler/glsl/glcpp/tests/089-redefine-macro-error.c
new file mode 100644
index 00000000000..b3d1391e160
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/089-redefine-macro-error.c
@@ -0,0 +1,17 @@
+#define x y
+#define x z
+
+#define abc 123
+#define abc() 123
+
+#define foo() bar
+#define foo(x) bar
+
+#define bar() baz
+#define bar baz
+
+#define biff(a,b) a+b
+#define biff(a,b,c) a+b
+
+#define oper(a,b) a+b
+#define oper(a,b) a*b
diff --git a/src/compiler/glsl/glcpp/tests/089-redefine-macro-error.c.expected b/src/compiler/glsl/glcpp/tests/089-redefine-macro-error.c.expected
new file mode 100644
index 00000000000..a945161497f
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/089-redefine-macro-error.c.expected
@@ -0,0 +1,29 @@
+0:2(9): preprocessor error: Redefinition of macro x
+
+0:5(9): preprocessor error: Redefinition of macro abc
+
+0:8(9): preprocessor error: Redefinition of macro foo
+
+0:11(9): preprocessor error: Redefinition of macro bar
+
+0:14(9): preprocessor error: Redefinition of macro biff
+
+0:17(9): preprocessor error: Redefinition of macro oper
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/compiler/glsl/glcpp/tests/090-hash-error.c b/src/compiler/glsl/glcpp/tests/090-hash-error.c
new file mode 100644
index 00000000000..d19bb7faed8
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/090-hash-error.c
@@ -0,0 +1 @@
+#error human error
diff --git a/src/compiler/glsl/glcpp/tests/090-hash-error.c.expected b/src/compiler/glsl/glcpp/tests/090-hash-error.c.expected
new file mode 100644
index 00000000000..876a6ea9cc5
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/090-hash-error.c.expected
@@ -0,0 +1 @@
+0:1(1): preprocessor error: #error human error
diff --git a/src/compiler/glsl/glcpp/tests/091-hash-line.c b/src/compiler/glsl/glcpp/tests/091-hash-line.c
new file mode 100644
index 00000000000..26d70382a89
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/091-hash-line.c
@@ -0,0 +1,14 @@
+#line 0
+#error line 0 error
+#line 25
+#error line 25 error
+#line 0 1
+#error source 1, line 0 error
+#line 30 2
+#error source 2, line 30 error
+#line 45 2 /* A line with a comment */
+#define NINETY 90
+#define TWO 2
+#line NINETY TWO /* A #line line with macro expansion */
+#define FUNCTION_LIKE_MACRO(source, line) source line
+#line FUNCTION_LIKE_MACRO(180,2)
diff --git a/src/compiler/glsl/glcpp/tests/091-hash-line.c.expected b/src/compiler/glsl/glcpp/tests/091-hash-line.c.expected
new file mode 100644
index 00000000000..ac9ab252f1e
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/091-hash-line.c.expected
@@ -0,0 +1,14 @@
+0:0(1): preprocessor error: #error line 0 error
+0:25(1): preprocessor error: #error line 25 error
+1:0(1): preprocessor error: #error source 1, line 0 error
+2:30(1): preprocessor error: #error source 2, line 30 error
+#line 0
+#line 25
+#line 0 1
+#line 30 2
+#line 45 2
+
+
+#line 90 2
+
+#line 180 2
diff --git a/src/compiler/glsl/glcpp/tests/092-redefine-macro-error-2.c b/src/compiler/glsl/glcpp/tests/092-redefine-macro-error-2.c
new file mode 100644
index 00000000000..3c161a5c501
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/092-redefine-macro-error-2.c
@@ -0,0 +1,5 @@
+#define A
+#define A 1
+
+#define B 1
+#define B
diff --git a/src/compiler/glsl/glcpp/tests/092-redefine-macro-error-2.c.expected b/src/compiler/glsl/glcpp/tests/092-redefine-macro-error-2.c.expected
new file mode 100644
index 00000000000..698294d91f2
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/092-redefine-macro-error-2.c.expected
@@ -0,0 +1,9 @@
+0:2(9): preprocessor error: Redefinition of macro A
+
+0:5(9): preprocessor error: Redefinition of macro B
+
+
+
+
+
+
diff --git a/src/compiler/glsl/glcpp/tests/093-divide-by-zero.c b/src/compiler/glsl/glcpp/tests/093-divide-by-zero.c
new file mode 100644
index 00000000000..bf65d4f5271
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/093-divide-by-zero.c
@@ -0,0 +1,2 @@
+#if (1 / 0)
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/093-divide-by-zero.c.expected b/src/compiler/glsl/glcpp/tests/093-divide-by-zero.c.expected
new file mode 100644
index 00000000000..a858870b794
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/093-divide-by-zero.c.expected
@@ -0,0 +1,3 @@
+0:1(12): preprocessor error: division by 0 in preprocessor directive
+
+
diff --git a/src/compiler/glsl/glcpp/tests/094-divide-by-zero-short-circuit.c b/src/compiler/glsl/glcpp/tests/094-divide-by-zero-short-circuit.c
new file mode 100644
index 00000000000..04497b17913
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/094-divide-by-zero-short-circuit.c
@@ -0,0 +1,13 @@
+/* glcpp is generating a division-by-zero error for this case. It's
+ * easy to argue that it should be short-circuiting the evaluation and
+ * not generating the diagnostic (which happens to be what gcc does).
+ * But it doesn't seem like we should force this behavior on our
+ * pre-processor, (and, as always, the GLSL specification of the
+ * pre-processor is too vague on this point).
+ *
+ * If a short-circuit evaluation optimization does get added to the
+ * pre-processor then it would legitimate to update the expected file
+ * for this test.
+*/
+#if 1 || (1 / 0)
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/094-divide-by-zero-short-circuit.c.expected b/src/compiler/glsl/glcpp/tests/094-divide-by-zero-short-circuit.c.expected
new file mode 100644
index 00000000000..570952b2454
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/094-divide-by-zero-short-circuit.c.expected
@@ -0,0 +1,14 @@
+0:12(17): preprocessor error: division by 0 in preprocessor directive
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/compiler/glsl/glcpp/tests/095-recursive-define.c b/src/compiler/glsl/glcpp/tests/095-recursive-define.c
new file mode 100644
index 00000000000..801d90ce2e3
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/095-recursive-define.c
@@ -0,0 +1,3 @@
+#define A(a, b) B(a, b)
+#define C A(0, C)
+C
diff --git a/src/compiler/glsl/glcpp/tests/095-recursive-define.c.expected b/src/compiler/glsl/glcpp/tests/095-recursive-define.c.expected
new file mode 100644
index 00000000000..493ab091be7
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/095-recursive-define.c.expected
@@ -0,0 +1,3 @@
+
+
+B(0, C)
diff --git a/src/compiler/glsl/glcpp/tests/096-paste-twice.c b/src/compiler/glsl/glcpp/tests/096-paste-twice.c
new file mode 100644
index 00000000000..8da756fcba4
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/096-paste-twice.c
@@ -0,0 +1,3 @@
+#define paste_twice(a,b,c) a ## b ## c
+paste_twice(just, one, token)
+
diff --git a/src/compiler/glsl/glcpp/tests/096-paste-twice.c.expected b/src/compiler/glsl/glcpp/tests/096-paste-twice.c.expected
new file mode 100644
index 00000000000..96c57d2a6ec
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/096-paste-twice.c.expected
@@ -0,0 +1,3 @@
+
+justonetoken
+
diff --git a/src/compiler/glsl/glcpp/tests/097-paste-with-non-function-macro.c b/src/compiler/glsl/glcpp/tests/097-paste-with-non-function-macro.c
new file mode 100644
index 00000000000..0f46835c29e
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/097-paste-with-non-function-macro.c
@@ -0,0 +1,3 @@
+#define PASTE_MACRO one ## token
+PASTE_MACRO
+
diff --git a/src/compiler/glsl/glcpp/tests/097-paste-with-non-function-macro.c.expected b/src/compiler/glsl/glcpp/tests/097-paste-with-non-function-macro.c.expected
new file mode 100644
index 00000000000..36f66992539
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/097-paste-with-non-function-macro.c.expected
@@ -0,0 +1,3 @@
+
+onetoken
+
diff --git a/src/compiler/glsl/glcpp/tests/098-elif-undefined.c b/src/compiler/glsl/glcpp/tests/098-elif-undefined.c
new file mode 100644
index 00000000000..1f520d4d432
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/098-elif-undefined.c
@@ -0,0 +1,7 @@
+#if 0
+Not this
+#elif UNDEFINED_MACRO
+Nor this
+#else
+Yes, this.
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/098-elif-undefined.c.expected b/src/compiler/glsl/glcpp/tests/098-elif-undefined.c.expected
new file mode 100644
index 00000000000..c6ef689ce4b
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/098-elif-undefined.c.expected
@@ -0,0 +1,7 @@
+
+
+
+
+
+Yes, this.
+
diff --git a/src/compiler/glsl/glcpp/tests/099-c99-example.c b/src/compiler/glsl/glcpp/tests/099-c99-example.c
new file mode 100644
index 00000000000..d1976b1f265
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/099-c99-example.c
@@ -0,0 +1,17 @@
+#define x 3
+#define f(a) f(x * (a))
+#undef x
+#define x 2
+#define g f
+#define z z[0]
+#define h g(~
+#define m(a) a(w)
+#define w 0,1
+#define t(a) a
+#define p() int
+#define q(x) x
+#define r(x,y) x ## y
+f(y+1) + f(f(z)) % t(t(g)(0) + t)(1);
+g(x +(3,4)-w) | h 5) & m
+ (f)^m(m);
+p() i[q()] = { q(1), r(2,3), r(4,), r(,5), r(,)};
diff --git a/src/compiler/glsl/glcpp/tests/099-c99-example.c.expected b/src/compiler/glsl/glcpp/tests/099-c99-example.c.expected
new file mode 100644
index 00000000000..352bbff48f5
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/099-c99-example.c.expected
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1);
+f(2 * (2 +(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1);
+int i[] = { 1, 23, 4, 5, };
diff --git a/src/compiler/glsl/glcpp/tests/100-macro-with-colon.c b/src/compiler/glsl/glcpp/tests/100-macro-with-colon.c
new file mode 100644
index 00000000000..31dbb9a9edc
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/100-macro-with-colon.c
@@ -0,0 +1,7 @@
+#define one 1
+#define two 2
+
+switch (1) {
+ case one + two:
+ break;
+}
diff --git a/src/compiler/glsl/glcpp/tests/100-macro-with-colon.c.expected b/src/compiler/glsl/glcpp/tests/100-macro-with-colon.c.expected
new file mode 100644
index 00000000000..09f1f417bdd
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/100-macro-with-colon.c.expected
@@ -0,0 +1,7 @@
+
+
+
+switch (1) {
+ case 1 + 2:
+ break;
+}
diff --git a/src/compiler/glsl/glcpp/tests/101-macros-used-twice.c b/src/compiler/glsl/glcpp/tests/101-macros-used-twice.c
new file mode 100644
index 00000000000..e1693805b6a
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/101-macros-used-twice.c
@@ -0,0 +1,16 @@
+#define object 1
+#define function(x) 1
+
+#if object
+once
+#endif
+#if object
+twice
+#endif
+
+#if function(0)
+once
+#endif
+#if function(0)
+once again
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/101-macros-used-twice.c.expected b/src/compiler/glsl/glcpp/tests/101-macros-used-twice.c.expected
new file mode 100644
index 00000000000..1e0b30696cb
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/101-macros-used-twice.c.expected
@@ -0,0 +1,16 @@
+
+
+
+
+once
+
+
+twice
+
+
+
+once
+
+
+once again
+
diff --git a/src/compiler/glsl/glcpp/tests/102-garbage-after-endif.c b/src/compiler/glsl/glcpp/tests/102-garbage-after-endif.c
new file mode 100644
index 00000000000..301779eb948
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/102-garbage-after-endif.c
@@ -0,0 +1,2 @@
+#if 0
+#endif garbage
diff --git a/src/compiler/glsl/glcpp/tests/102-garbage-after-endif.c.expected b/src/compiler/glsl/glcpp/tests/102-garbage-after-endif.c.expected
new file mode 100644
index 00000000000..d9f3bdc9465
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/102-garbage-after-endif.c.expected
@@ -0,0 +1,2 @@
+0:2(8): preprocessor error: syntax error, unexpected IDENTIFIER, expecting NEWLINE
+
diff --git a/src/compiler/glsl/glcpp/tests/103-garbage-after-else-0.c b/src/compiler/glsl/glcpp/tests/103-garbage-after-else-0.c
new file mode 100644
index 00000000000..c460feadf57
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/103-garbage-after-else-0.c
@@ -0,0 +1,3 @@
+#if 0
+#else garbage
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/103-garbage-after-else-0.c.expected b/src/compiler/glsl/glcpp/tests/103-garbage-after-else-0.c.expected
new file mode 100644
index 00000000000..b053b399775
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/103-garbage-after-else-0.c.expected
@@ -0,0 +1,4 @@
+0:2(7): preprocessor error: syntax error, unexpected IDENTIFIER, expecting NEWLINE
+0:1(6): preprocessor error: Unterminated #if
+
+
diff --git a/src/compiler/glsl/glcpp/tests/104-hash-line-followed-by-code.c b/src/compiler/glsl/glcpp/tests/104-hash-line-followed-by-code.c
new file mode 100644
index 00000000000..3fbeec48e4c
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/104-hash-line-followed-by-code.c
@@ -0,0 +1,2 @@
+#line 2
+int foo();
diff --git a/src/compiler/glsl/glcpp/tests/104-hash-line-followed-by-code.c.expected b/src/compiler/glsl/glcpp/tests/104-hash-line-followed-by-code.c.expected
new file mode 100644
index 00000000000..3fbeec48e4c
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/104-hash-line-followed-by-code.c.expected
@@ -0,0 +1,2 @@
+#line 2
+int foo();
diff --git a/src/compiler/glsl/glcpp/tests/105-multiline-hash-line.c b/src/compiler/glsl/glcpp/tests/105-multiline-hash-line.c
new file mode 100644
index 00000000000..da156c6a596
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/105-multiline-hash-line.c
@@ -0,0 +1,5 @@
+#define X(x) x
+#line X( \
+ 1 \
+ )
+#line 2
diff --git a/src/compiler/glsl/glcpp/tests/105-multiline-hash-line.c.expected b/src/compiler/glsl/glcpp/tests/105-multiline-hash-line.c.expected
new file mode 100644
index 00000000000..814cef1b8c5
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/105-multiline-hash-line.c.expected
@@ -0,0 +1,5 @@
+
+#line 1
+
+
+#line 2
diff --git a/src/compiler/glsl/glcpp/tests/106-multiline-hash-if.c b/src/compiler/glsl/glcpp/tests/106-multiline-hash-if.c
new file mode 100644
index 00000000000..929e93e782f
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/106-multiline-hash-if.c
@@ -0,0 +1,6 @@
+#define X(x) x
+#if X( \
+ 1 \
+ )
+int foo();
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/106-multiline-hash-if.c.expected b/src/compiler/glsl/glcpp/tests/106-multiline-hash-if.c.expected
new file mode 100644
index 00000000000..1c0cbc970f5
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/106-multiline-hash-if.c.expected
@@ -0,0 +1,6 @@
+
+
+
+
+int foo();
+
diff --git a/src/compiler/glsl/glcpp/tests/107-multiline-hash-elif.c b/src/compiler/glsl/glcpp/tests/107-multiline-hash-elif.c
new file mode 100644
index 00000000000..8c1c67a4d6b
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/107-multiline-hash-elif.c
@@ -0,0 +1,7 @@
+#define X(x) x
+#if 0
+#elif X( \
+ 1 \
+ )
+int foo();
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/107-multiline-hash-elif.c.expected b/src/compiler/glsl/glcpp/tests/107-multiline-hash-elif.c.expected
new file mode 100644
index 00000000000..b0601d7ee42
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/107-multiline-hash-elif.c.expected
@@ -0,0 +1,7 @@
+
+
+
+
+
+int foo();
+
diff --git a/src/compiler/glsl/glcpp/tests/108-no-space-after-hash-version.c b/src/compiler/glsl/glcpp/tests/108-no-space-after-hash-version.c
new file mode 100644
index 00000000000..0ce36f2eb1b
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/108-no-space-after-hash-version.c
@@ -0,0 +1 @@
+#version110
diff --git a/src/compiler/glsl/glcpp/tests/108-no-space-after-hash-version.c.expected b/src/compiler/glsl/glcpp/tests/108-no-space-after-hash-version.c.expected
new file mode 100644
index 00000000000..4f4243f947f
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/108-no-space-after-hash-version.c.expected
@@ -0,0 +1 @@
+0:1(1): preprocessor error: Illegal non-directive after #
diff --git a/src/compiler/glsl/glcpp/tests/109-no-space-after-hash-line.c b/src/compiler/glsl/glcpp/tests/109-no-space-after-hash-line.c
new file mode 100644
index 00000000000..f52966a8e80
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/109-no-space-after-hash-line.c
@@ -0,0 +1 @@
+#line2
diff --git a/src/compiler/glsl/glcpp/tests/109-no-space-after-hash-line.c.expected b/src/compiler/glsl/glcpp/tests/109-no-space-after-hash-line.c.expected
new file mode 100644
index 00000000000..4f4243f947f
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/109-no-space-after-hash-line.c.expected
@@ -0,0 +1 @@
+0:1(1): preprocessor error: Illegal non-directive after #
diff --git a/src/compiler/glsl/glcpp/tests/110-no-space-digits-after-hash-elif.c b/src/compiler/glsl/glcpp/tests/110-no-space-digits-after-hash-elif.c
new file mode 100644
index 00000000000..6d7d0f38d9a
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/110-no-space-digits-after-hash-elif.c
@@ -0,0 +1,3 @@
+#if 1
+#elif110
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/110-no-space-digits-after-hash-elif.c.expected b/src/compiler/glsl/glcpp/tests/110-no-space-digits-after-hash-elif.c.expected
new file mode 100644
index 00000000000..4d93de41dd3
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/110-no-space-digits-after-hash-elif.c.expected
@@ -0,0 +1,3 @@
+0:2(1): preprocessor error: Illegal non-directive after #
+
+
diff --git a/src/compiler/glsl/glcpp/tests/111-no-space-operator-after-hash-if.c b/src/compiler/glsl/glcpp/tests/111-no-space-operator-after-hash-if.c
new file mode 100644
index 00000000000..b3413371ec2
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/111-no-space-operator-after-hash-if.c
@@ -0,0 +1,19 @@
+#if(1)
+success
+#endif
+
+#if+1
+success
+#endif
+
+#if-1
+success
+#endif
+
+#if!1
+success
+#endif
+
+#if~1
+success
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/111-no-space-operator-after-hash-if.c.expected b/src/compiler/glsl/glcpp/tests/111-no-space-operator-after-hash-if.c.expected
new file mode 100644
index 00000000000..5c005c393a9
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/111-no-space-operator-after-hash-if.c.expected
@@ -0,0 +1,19 @@
+
+success
+
+
+
+success
+
+
+
+success
+
+
+
+
+
+
+
+success
+
diff --git a/src/compiler/glsl/glcpp/tests/112-no-space-operator-after-hash-elif.c b/src/compiler/glsl/glcpp/tests/112-no-space-operator-after-hash-elif.c
new file mode 100644
index 00000000000..e8221bc49c3
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/112-no-space-operator-after-hash-elif.c
@@ -0,0 +1,24 @@
+#if 0
+#elif(1)
+success
+#endif
+
+#if 0
+#elif+1
+success
+#endif
+
+#if 0
+#elif-1
+success
+#endif
+
+#if 0
+#elif!1
+success
+#endif
+
+#if 0
+#elif~1
+success
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/112-no-space-operator-after-hash-elif.c.expected b/src/compiler/glsl/glcpp/tests/112-no-space-operator-after-hash-elif.c.expected
new file mode 100644
index 00000000000..86b37036b65
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/112-no-space-operator-after-hash-elif.c.expected
@@ -0,0 +1,24 @@
+
+
+success
+
+
+
+
+success
+
+
+
+
+success
+
+
+
+
+
+
+
+
+
+success
+
diff --git a/src/compiler/glsl/glcpp/tests/113-line-and-file-macros.c b/src/compiler/glsl/glcpp/tests/113-line-and-file-macros.c
new file mode 100644
index 00000000000..369c4879260
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/113-line-and-file-macros.c
@@ -0,0 +1,7 @@
+1. Number of dalmations: __LINE__ __FILE__ __LINE__
+2. Nominal visual acuity: __LINE__ __FILE__ / __LINE__ __FILE__
+3. Battle of Thermopylae, as film: __LINE__ __FILE__ __FILE__
+4. HTTP code for "Not Found": __LINE__ __FILE__ __LINE__
+5. Hexadecimal for 20560: __LINE__ __FILE__ __LINE__ __FILE__
+6: Zip code for Nortonville, KS: __LINE__ __LINE__ __FILE__ __LINE__ __FILE__
+7. James Bond, as a number: __FILE__ __FILE__ __LINE__
diff --git a/src/compiler/glsl/glcpp/tests/113-line-and-file-macros.c.expected b/src/compiler/glsl/glcpp/tests/113-line-and-file-macros.c.expected
new file mode 100644
index 00000000000..55bc788ffd7
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/113-line-and-file-macros.c.expected
@@ -0,0 +1,7 @@
+1. Number of dalmations: 1 0 1
+2. Nominal visual acuity: 2 0 / 2 0
+3. Battle of Thermopylae, as film: 3 0 0
+4. HTTP code for "Not Found": 4 0 4
+5. Hexadecimal for 20560: 5 0 5 0
+6: Zip code for Nortonville, KS: 6 6 0 6 0
+7. James Bond, as a number: 0 0 7
diff --git a/src/compiler/glsl/glcpp/tests/114-paste-integer-tokens.c b/src/compiler/glsl/glcpp/tests/114-paste-integer-tokens.c
new file mode 100644
index 00000000000..d80d9c7ef4b
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/114-paste-integer-tokens.c
@@ -0,0 +1,7 @@
+#define PASTE3(a,b,c) a ## b ## c
+#define PASTE4(a,b,c,d) a ## b ## c ## d
+#define PASTE5(a,b,c,d,e) a ## b ## c ## d ## e
+4. HTTP code for "Not Found": PASTE3(__LINE__, __FILE__ , __LINE__)
+5. Hexadecimal for 20560: PASTE4(__LINE__, __FILE__, __LINE__, __FILE__)
+6: Zip code for Nortonville, KS: PASTE5(__LINE__, __LINE__, __FILE__, __LINE__, __FILE__)
+7. James Bond, as a number: PASTE3(__FILE__, __FILE__, __LINE__)
diff --git a/src/compiler/glsl/glcpp/tests/114-paste-integer-tokens.c.expected b/src/compiler/glsl/glcpp/tests/114-paste-integer-tokens.c.expected
new file mode 100644
index 00000000000..aa9711034a6
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/114-paste-integer-tokens.c.expected
@@ -0,0 +1,7 @@
+
+
+
+4. HTTP code for "Not Found": 404
+5. Hexadecimal for 20560: 5050
+6: Zip code for Nortonville, KS: 66060
+7. James Bond, as a number: 007
diff --git a/src/compiler/glsl/glcpp/tests/115-line-continuations.c b/src/compiler/glsl/glcpp/tests/115-line-continuations.c
new file mode 100644
index 00000000000..105590d85ed
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/115-line-continuations.c
@@ -0,0 +1,9 @@
+// This comment continues to the next line, hiding the define \
+#define CONTINUATION_UNSUPPORTED
+
+#ifdef CONTINUATION_UNSUPPORTED
+failure
+#else
+success
+#endif
+
diff --git a/src/compiler/glsl/glcpp/tests/115-line-continuations.c.expected b/src/compiler/glsl/glcpp/tests/115-line-continuations.c.expected
new file mode 100644
index 00000000000..428b5e822c5
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/115-line-continuations.c.expected
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+success
+
+
diff --git a/src/compiler/glsl/glcpp/tests/116-disable-line-continuations.c b/src/compiler/glsl/glcpp/tests/116-disable-line-continuations.c
new file mode 100644
index 00000000000..83d5ddf681b
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/116-disable-line-continuations.c
@@ -0,0 +1,13 @@
+// glcpp-args: --disable-line-continuations
+
+// This comments ends with a backslash \\
+#define NO_CONTINUATION
+
+#ifdef NO_CONTINUATION
+success
+#else
+failure
+#endif
+
+
+
diff --git a/src/compiler/glsl/glcpp/tests/116-disable-line-continuations.c.expected b/src/compiler/glsl/glcpp/tests/116-disable-line-continuations.c.expected
new file mode 100644
index 00000000000..5ca78928a61
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/116-disable-line-continuations.c.expected
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+success
+
+
+
+
+
+
diff --git a/src/compiler/glsl/glcpp/tests/117-line-continuation-and-non-continuation-backslash.c b/src/compiler/glsl/glcpp/tests/117-line-continuation-and-non-continuation-backslash.c
new file mode 100644
index 00000000000..6a6f2829883
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/117-line-continuation-and-non-continuation-backslash.c
@@ -0,0 +1,12 @@
+/* This test case is the minimal case to replicate the bug reported here:
+ *
+ * https://bugs.freedesktop.org/show_bug.cgi?id=65112
+ *
+ * To trigger the bug, there must be a line-continuation sequence
+ * (backslash newline), then an additional newline character, and
+ * finally another backslash that is not part of a line-continuation
+ * sequence.
+ */
+\
+
+/* \ */
diff --git a/src/compiler/glsl/glcpp/tests/117-line-continuation-and-non-continuation-backslash.c.expected b/src/compiler/glsl/glcpp/tests/117-line-continuation-and-non-continuation-backslash.c.expected
new file mode 100644
index 00000000000..8aaa04d28e4
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/117-line-continuation-and-non-continuation-backslash.c.expected
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/compiler/glsl/glcpp/tests/118-comment-becomes-space.c b/src/compiler/glsl/glcpp/tests/118-comment-becomes-space.c
new file mode 100644
index 00000000000..53e80394ab6
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/118-comment-becomes-space.c
@@ -0,0 +1,4 @@
+#define FOO first/*
+*/second
+
+FOO
diff --git a/src/compiler/glsl/glcpp/tests/118-comment-becomes-space.c.expected b/src/compiler/glsl/glcpp/tests/118-comment-becomes-space.c.expected
new file mode 100644
index 00000000000..1fa8135cb13
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/118-comment-becomes-space.c.expected
@@ -0,0 +1,4 @@
+
+
+
+first second
diff --git a/src/compiler/glsl/glcpp/tests/119-elif-after-else.c b/src/compiler/glsl/glcpp/tests/119-elif-after-else.c
new file mode 100644
index 00000000000..9b9e9233bcb
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/119-elif-after-else.c
@@ -0,0 +1,6 @@
+#if 0
+#else
+int foo;
+#elif 0
+int bar;
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/119-elif-after-else.c.expected b/src/compiler/glsl/glcpp/tests/119-elif-after-else.c.expected
new file mode 100644
index 00000000000..636956799cd
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/119-elif-after-else.c.expected
@@ -0,0 +1,7 @@
+0:4(1): preprocessor error: #elif after #else
+
+
+int foo;
+
+int bar;
+
diff --git a/src/compiler/glsl/glcpp/tests/120-undef-builtin.c b/src/compiler/glsl/glcpp/tests/120-undef-builtin.c
new file mode 100644
index 00000000000..49e7696613e
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/120-undef-builtin.c
@@ -0,0 +1,3 @@
+#undef __LINE__
+#undef __FILE__
+#undef __VERSION__
diff --git a/src/compiler/glsl/glcpp/tests/120-undef-builtin.c.expected b/src/compiler/glsl/glcpp/tests/120-undef-builtin.c.expected
new file mode 100644
index 00000000000..3b736df378e
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/120-undef-builtin.c.expected
@@ -0,0 +1,6 @@
+0:1(1): preprocessor error: Built-in (pre-defined) macro names cannot be undefined.
+0:2(1): preprocessor error: Built-in (pre-defined) macro names cannot be undefined.
+0:3(1): preprocessor error: Built-in (pre-defined) macro names cannot be undefined.
+
+
+
diff --git a/src/compiler/glsl/glcpp/tests/121-comment-bug-72686.c b/src/compiler/glsl/glcpp/tests/121-comment-bug-72686.c
new file mode 100644
index 00000000000..67ebe73e5cf
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/121-comment-bug-72686.c
@@ -0,0 +1,2 @@
+/*
+ */ //
diff --git a/src/compiler/glsl/glcpp/tests/121-comment-bug-72686.c.expected b/src/compiler/glsl/glcpp/tests/121-comment-bug-72686.c.expected
new file mode 100644
index 00000000000..8cb7cb9891f
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/121-comment-bug-72686.c.expected
@@ -0,0 +1,2 @@
+
+
diff --git a/src/compiler/glsl/glcpp/tests/122-redefine-whitespace.c b/src/compiler/glsl/glcpp/tests/122-redefine-whitespace.c
new file mode 100644
index 00000000000..ae7ea09f67e
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/122-redefine-whitespace.c
@@ -0,0 +1,16 @@
+/* Original definitions. */
+#define TWO ( 1+1 )
+#define FOUR (2 + 2)
+#define SIX (3 + 3)
+
+/* Redefinitions with whitespace in same places, but different amounts, (so no
+ * error). */
+#define TWO ( 1+1 )
+#define FOUR (2 + 2)
+#define SIX (3/*comment is whitespace*/+ /* collapsed */ /* to */ /* one */ /* space */ 3)
+
+/* Redefinitions with whitespace in different places. Each of these should
+ * trigger an error. */
+#define TWO (1 + 1)
+#define FOUR ( 2+2 )
+#define SIX (/*not*/3 + 3/*expected*/)
diff --git a/src/compiler/glsl/glcpp/tests/122-redefine-whitespace.c.expected b/src/compiler/glsl/glcpp/tests/122-redefine-whitespace.c.expected
new file mode 100644
index 00000000000..602bdef94c2
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/122-redefine-whitespace.c.expected
@@ -0,0 +1,22 @@
+0:14(9): preprocessor error: Redefinition of macro TWO
+
+0:15(9): preprocessor error: Redefinition of macro FOUR
+
+0:16(9): preprocessor error: Redefinition of macro SIX
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/compiler/glsl/glcpp/tests/123-garbage-after-else-1.c b/src/compiler/glsl/glcpp/tests/123-garbage-after-else-1.c
new file mode 100644
index 00000000000..0b341a381f8
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/123-garbage-after-else-1.c
@@ -0,0 +1,3 @@
+#if 1
+#else garbage
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/123-garbage-after-else-1.c.expected b/src/compiler/glsl/glcpp/tests/123-garbage-after-else-1.c.expected
new file mode 100644
index 00000000000..b053b399775
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/123-garbage-after-else-1.c.expected
@@ -0,0 +1,4 @@
+0:2(7): preprocessor error: syntax error, unexpected IDENTIFIER, expecting NEWLINE
+0:1(6): preprocessor error: Unterminated #if
+
+
diff --git a/src/compiler/glsl/glcpp/tests/124-preprocessing-numbers.c b/src/compiler/glsl/glcpp/tests/124-preprocessing-numbers.c
new file mode 100644
index 00000000000..947ba1885ec
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/124-preprocessing-numbers.c
@@ -0,0 +1,37 @@
+#define e THIS_SHOULD_NOT_BE_EXPANDED
+#define E NOR_THIS
+#define p NOT_THIS_EITHER
+#define P AND_SURELY_NOT_THIS
+#define OK CRAZY_BUT_TRUE_THIS_NEITHER
+
+/* This one is actually meant to be expanded */
+#define MUST_EXPAND GO
+
+/* The following are "preprocessing numbers" and should not trigger macro
+ * expansion. */
+1e
+1OK
+
+/* These are also "preprocessing numbers", so no expansion */
+123e+OK
+.23E+OK
+1.3e-OK
+12.E-OK
+123p+OK
+.23P+OK
+1.3p-OK
+12.P-OK
+123..OK
+.23.OK.OK
+
+/* Importantly, just before the MUST_EXPAND in each of these, the preceding
+ * "preprocessing number" ends and we have an actual expression. So the
+ * MUST_EXPAND macro must be expanded (who would have though?) in each case. */
+123ef+MUST_EXPAND
+.23E3-MUST_EXPAND
+1.3e--MUST_EXPAND
+12.E-&MUST_EXPAND
+123p+OK+MUST_EXPAND
+.23P+OK;MUST_EXPAND
+1.3p-OK-MUST_EXPAND
+12.P-OK&MUST_EXPAND
diff --git a/src/compiler/glsl/glcpp/tests/124-preprocessing-numbers.c.expected b/src/compiler/glsl/glcpp/tests/124-preprocessing-numbers.c.expected
new file mode 100644
index 00000000000..6ec588862d6
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/124-preprocessing-numbers.c.expected
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+1e
+1OK
+
+
+123e+OK
+.23E+OK
+1.3e-OK
+12.E-OK
+123p+OK
+.23P+OK
+1.3p-OK
+12.P-OK
+123..OK
+.23.OK.OK
+
+
+
+
+123ef+GO
+.23E3-GO
+1.3e--GO
+12.E-&GO
+123p+OK+GO
+.23P+OK;GO
+1.3p-OK-GO
+12.P-OK&GO
diff --git a/src/compiler/glsl/glcpp/tests/125-es-short-circuit-undefined.c b/src/compiler/glsl/glcpp/tests/125-es-short-circuit-undefined.c
new file mode 100644
index 00000000000..4ee29f6d93f
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/125-es-short-circuit-undefined.c
@@ -0,0 +1,27 @@
+/* For GLSL in OpenGL ES, an undefined macro appearing in an #if or #elif
+ * expression, (other than as an argument to defined) is an error.
+ *
+ * Except in the case of a short-circuiting && or || operator, where the
+ * specification explicitly mandates that there be no error.
+ */
+#version 300 es
+
+/* These yield errors */
+#if NOT_DEFINED
+#endif
+
+#if 0
+#elif ALSO_NOT_DEFINED
+#endif
+
+/* But these yield no errors */
+#if 1 || STILL_NOT_DEFINED
+Success
+#endif
+
+#if 0
+#elif 0 && WILL_ANYONE_DEFINE_ANYTHING
+#else
+More success
+#endif
+
diff --git a/src/compiler/glsl/glcpp/tests/125-es-short-circuit-undefined.c.expected b/src/compiler/glsl/glcpp/tests/125-es-short-circuit-undefined.c.expected
new file mode 100644
index 00000000000..616aa912e2f
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/125-es-short-circuit-undefined.c.expected
@@ -0,0 +1,29 @@
+0:10(16): preprocessor error: undefined macro NOT_DEFINED in expression (illegal in GLES)
+0:14(23): preprocessor error: undefined macro ALSO_NOT_DEFINED in expression (illegal in GLES)
+
+
+
+
+
+
+#version 300 es
+
+
+
+
+
+
+
+
+
+
+
+Success
+
+
+
+
+
+More success
+
+
diff --git a/src/compiler/glsl/glcpp/tests/126-garbage-after-directive.c b/src/compiler/glsl/glcpp/tests/126-garbage-after-directive.c
new file mode 100644
index 00000000000..4c0d29000a3
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/126-garbage-after-directive.c
@@ -0,0 +1,5 @@
+#ifdef MACRO garbage
+#endif
+
+#ifndef MORE garbage
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/126-garbage-after-directive.c.expected b/src/compiler/glsl/glcpp/tests/126-garbage-after-directive.c.expected
new file mode 100644
index 00000000000..82a06f8a3b3
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/126-garbage-after-directive.c.expected
@@ -0,0 +1,7 @@
+0:1(14): preprocessor error: extra tokens at end of directive
+0:4(14): preprocessor error: extra tokens at end of directive
+
+
+
+
+
diff --git a/src/compiler/glsl/glcpp/tests/127-pragma-empty.c b/src/compiler/glsl/glcpp/tests/127-pragma-empty.c
new file mode 100644
index 00000000000..0f9b0b3d38f
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/127-pragma-empty.c
@@ -0,0 +1,3 @@
+/* It seems an odd (and particularly useless) thing to have an empty pragma,
+ * but we probably shouldn't trigger an error in this case. */
+#pragma
diff --git a/src/compiler/glsl/glcpp/tests/127-pragma-empty.c.expected b/src/compiler/glsl/glcpp/tests/127-pragma-empty.c.expected
new file mode 100644
index 00000000000..92371a07c32
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/127-pragma-empty.c.expected
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/compiler/glsl/glcpp/tests/128-space-before-hash.c b/src/compiler/glsl/glcpp/tests/128-space-before-hash.c
new file mode 100644
index 00000000000..fba9596baf8
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/128-space-before-hash.c
@@ -0,0 +1,21 @@
+ /* Any directive can be preceded by a space. */
+ #version 300
+ #pragma Testing spaces before hash
+ #
+ #line 3
+ #define FOO
+ #ifdef FOO
+ yes
+ #endif
+ #if 0
+ #elif defined FOO
+ yes again
+ #endif
+ #if 0
+ #else
+ for the third time, yes!
+ #endif
+ #undef FOO
+ #ifndef FOO
+ yes, of course
+ #endif
diff --git a/src/compiler/glsl/glcpp/tests/128-space-before-hash.c.expected b/src/compiler/glsl/glcpp/tests/128-space-before-hash.c.expected
new file mode 100644
index 00000000000..9babb6fb078
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/128-space-before-hash.c.expected
@@ -0,0 +1,21 @@
+
+#version 300
+#pragma Testing spaces before hash
+
+#line 3
+
+
+ yes
+
+
+
+ yes again
+
+
+
+ for the third time, yes!
+
+
+
+ yes, of course
+
diff --git a/src/compiler/glsl/glcpp/tests/129-define-non-identifier.c b/src/compiler/glsl/glcpp/tests/129-define-non-identifier.c
new file mode 100644
index 00000000000..a229179f18c
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/129-define-non-identifier.c
@@ -0,0 +1 @@
+#define 123 456
diff --git a/src/compiler/glsl/glcpp/tests/129-define-non-identifier.c.expected b/src/compiler/glsl/glcpp/tests/129-define-non-identifier.c.expected
new file mode 100644
index 00000000000..fd0b41347fa
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/129-define-non-identifier.c.expected
@@ -0,0 +1,2 @@
+0:1(9): preprocessor error: #define followed by a non-identifier: 123
+0:1(9): preprocessor error: syntax error, unexpected INTEGER_STRING, expecting FUNC_IDENTIFIER or OBJ_IDENTIFIER
diff --git a/src/compiler/glsl/glcpp/tests/130-define-comment.c b/src/compiler/glsl/glcpp/tests/130-define-comment.c
new file mode 100644
index 00000000000..33312362cc7
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/130-define-comment.c
@@ -0,0 +1,2 @@
+#define /*...*/ FUNC( /*...*/ x /*...*/ ) /*...*/ FOO( /*...*/ x /*...*/ )
+FUNC(bar)
diff --git a/src/compiler/glsl/glcpp/tests/130-define-comment.c.expected b/src/compiler/glsl/glcpp/tests/130-define-comment.c.expected
new file mode 100644
index 00000000000..d789e29d5a8
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/130-define-comment.c.expected
@@ -0,0 +1,2 @@
+
+FOO( bar )
diff --git a/src/compiler/glsl/glcpp/tests/131-eof-without-newline.c b/src/compiler/glsl/glcpp/tests/131-eof-without-newline.c
new file mode 100644
index 00000000000..240292dad01
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/131-eof-without-newline.c
@@ -0,0 +1 @@
+this file ends with no newline \ No newline at end of file
diff --git a/src/compiler/glsl/glcpp/tests/131-eof-without-newline.c.expected b/src/compiler/glsl/glcpp/tests/131-eof-without-newline.c.expected
new file mode 100644
index 00000000000..57800306322
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/131-eof-without-newline.c.expected
@@ -0,0 +1 @@
+this file ends with no newline
diff --git a/src/compiler/glsl/glcpp/tests/132-eof-without-newline-define.c b/src/compiler/glsl/glcpp/tests/132-eof-without-newline-define.c
new file mode 100644
index 00000000000..6795e35ea00
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/132-eof-without-newline-define.c
@@ -0,0 +1 @@
+#define \ No newline at end of file
diff --git a/src/compiler/glsl/glcpp/tests/132-eof-without-newline-define.c.expected b/src/compiler/glsl/glcpp/tests/132-eof-without-newline-define.c.expected
new file mode 100644
index 00000000000..341e5e2aa67
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/132-eof-without-newline-define.c.expected
@@ -0,0 +1 @@
+0:1(1): preprocessor error: #define without macro name
diff --git a/src/compiler/glsl/glcpp/tests/133-eof-without-newline-comment.c b/src/compiler/glsl/glcpp/tests/133-eof-without-newline-comment.c
new file mode 100644
index 00000000000..56ec5f722c0
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/133-eof-without-newline-comment.c
@@ -0,0 +1 @@
+This file ends with no newline within a comment /* \ No newline at end of file
diff --git a/src/compiler/glsl/glcpp/tests/133-eof-without-newline-comment.c.expected b/src/compiler/glsl/glcpp/tests/133-eof-without-newline-comment.c.expected
new file mode 100644
index 00000000000..d186f48761f
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/133-eof-without-newline-comment.c.expected
@@ -0,0 +1,2 @@
+0:1(51): preprocessor error: Unterminated comment
+This file ends with no newline within a comment
diff --git a/src/compiler/glsl/glcpp/tests/134-hash-comment-directive.c b/src/compiler/glsl/glcpp/tests/134-hash-comment-directive.c
new file mode 100644
index 00000000000..3015f0e886e
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/134-hash-comment-directive.c
@@ -0,0 +1,22 @@
+/*...*/ # /*...*/ version 300
+ /*...*/#/*...*/ extension whatever
+ /*..*/ # /*..*/ pragma ignored
+/**/ # /**/ line 4
+ /*...*/# /*...*/ ifdef NOT_DEFINED
+ /*...*/# /*...*/ else
+ /*..*/ #/*..*/ endif
+ /*...*/# /*...*/ ifndef ALSO_NOT_DEFINED
+ /*...*/# /*...*/ else
+ /*..*/ #/*..*/ endif
+/*...*/ # /*...*/ if 0
+ /*...*/#/*...*/ elif 1
+ /*..*/ # /*..*/ else
+ /**/ # /**/ endif
+ /*...*/# /*...*/ define FOO bar
+ /*..*/ #/*..*/ define FUNC() baz
+ /*..*/ # /*..*/ define FUNC2(a,b) b a
+FOO
+FUNC()
+FUNC2(x,y)
+
+
diff --git a/src/compiler/glsl/glcpp/tests/134-hash-comment-directive.c.expected b/src/compiler/glsl/glcpp/tests/134-hash-comment-directive.c.expected
new file mode 100644
index 00000000000..760c960cb62
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/134-hash-comment-directive.c.expected
@@ -0,0 +1,22 @@
+#version 300
+#extension whatever
+#pragma ignored
+#line 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+bar
+baz
+y x
+
+
diff --git a/src/compiler/glsl/glcpp/tests/135-duplicate-parameter.c b/src/compiler/glsl/glcpp/tests/135-duplicate-parameter.c
new file mode 100644
index 00000000000..fd96bd64c74
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/135-duplicate-parameter.c
@@ -0,0 +1,2 @@
+#define FOO(a,a) which a?
+#define BAR(x,y,z,x) so very x
diff --git a/src/compiler/glsl/glcpp/tests/135-duplicate-parameter.c.expected b/src/compiler/glsl/glcpp/tests/135-duplicate-parameter.c.expected
new file mode 100644
index 00000000000..bc1a334ed29
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/135-duplicate-parameter.c.expected
@@ -0,0 +1,4 @@
+0:1(9): preprocessor error: Duplicate macro parameter "a"
+0:2(9): preprocessor error: Duplicate macro parameter "x"
+
+
diff --git a/src/compiler/glsl/glcpp/tests/136-plus-plus-and-minus-minus.c b/src/compiler/glsl/glcpp/tests/136-plus-plus-and-minus-minus.c
new file mode 100644
index 00000000000..167d3c8a3cf
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/136-plus-plus-and-minus-minus.c
@@ -0,0 +1,8 @@
+/* The body can include C expressions with ++ and -- */
+a = x++;
+b = ++x;
+c = x--;
+d = --x;
+/* But these are not legal in preprocessor expressions. */
+#if x++ > 4
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/136-plus-plus-and-minus-minus.c.expected b/src/compiler/glsl/glcpp/tests/136-plus-plus-and-minus-minus.c.expected
new file mode 100644
index 00000000000..137921b1695
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/136-plus-plus-and-minus-minus.c.expected
@@ -0,0 +1,8 @@
+0:7(12): preprocessor error: syntax error, unexpected PLUS_PLUS
+
+a = x++;
+b = ++x;
+c = x--;
+d = --x;
+
+
diff --git a/src/compiler/glsl/glcpp/tests/137-expand-macro-after-period.c b/src/compiler/glsl/glcpp/tests/137-expand-macro-after-period.c
new file mode 100644
index 00000000000..c8cd47fb57e
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/137-expand-macro-after-period.c
@@ -0,0 +1,4 @@
+#define FIELD(x) foo.x
+#define FIELD_OF(s, x) s.x
+FIELD(bar)
+FIELD_OF(foo, bar)
diff --git a/src/compiler/glsl/glcpp/tests/137-expand-macro-after-period.c.expected b/src/compiler/glsl/glcpp/tests/137-expand-macro-after-period.c.expected
new file mode 100644
index 00000000000..f9f5be13e01
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/137-expand-macro-after-period.c.expected
@@ -0,0 +1,4 @@
+
+
+foo.bar
+foo.bar
diff --git a/src/compiler/glsl/glcpp/tests/138-multi-line-comment-in-if-0.c b/src/compiler/glsl/glcpp/tests/138-multi-line-comment-in-if-0.c
new file mode 100644
index 00000000000..38967dc57d1
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/138-multi-line-comment-in-if-0.c
@@ -0,0 +1,7 @@
+#if 0
+/*
+ * This multi-line comment needs to be 3 lines to test what's intended.
+ */
+#else
+SUCCESS
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/138-multi-line-comment-in-if-0.c.expected b/src/compiler/glsl/glcpp/tests/138-multi-line-comment-in-if-0.c.expected
new file mode 100644
index 00000000000..0d6ef4d9ad4
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/138-multi-line-comment-in-if-0.c.expected
@@ -0,0 +1,7 @@
+
+
+
+
+
+SUCCESS
+
diff --git a/src/compiler/glsl/glcpp/tests/139-define-without-macro-name.c b/src/compiler/glsl/glcpp/tests/139-define-without-macro-name.c
new file mode 100644
index 00000000000..30e128db4c5
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/139-define-without-macro-name.c
@@ -0,0 +1,5 @@
+#define
+#define
+#define /*...*/
+#define //...
+Errors expected because no macro name is ever given!
diff --git a/src/compiler/glsl/glcpp/tests/139-define-without-macro-name.c.expected b/src/compiler/glsl/glcpp/tests/139-define-without-macro-name.c.expected
new file mode 100644
index 00000000000..42b02d1a8a1
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/139-define-without-macro-name.c.expected
@@ -0,0 +1,5 @@
+0:1(1): preprocessor error: #define without macro name
+0:2(1): preprocessor error: #define without macro name
+0:3(1): preprocessor error: #define without macro name
+0:4(1): preprocessor error: #define without macro name
+Errors expected because no macro name is ever given!
diff --git a/src/compiler/glsl/glcpp/tests/140-null-directive.c b/src/compiler/glsl/glcpp/tests/140-null-directive.c
new file mode 100644
index 00000000000..1dcb26ef8b9
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/140-null-directive.c
@@ -0,0 +1,9 @@
+/* GLSL accepts a null directive. Let's test that in several variations: */
+#
+ #
+/*....*/#/*....*/
+ /*..*/ # /*..*/
+#//...
+ # //...
+/*....*/#/**///..
+ /*..*/ # /**/ //
diff --git a/src/compiler/glsl/glcpp/tests/140-null-directive.c.expected b/src/compiler/glsl/glcpp/tests/140-null-directive.c.expected
new file mode 100644
index 00000000000..fa103f60e82
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/140-null-directive.c.expected
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/compiler/glsl/glcpp/tests/141-pragma-and-__LINE__.c b/src/compiler/glsl/glcpp/tests/141-pragma-and-__LINE__.c
new file mode 100644
index 00000000000..a93f3ce35fd
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/141-pragma-and-__LINE__.c
@@ -0,0 +1,6 @@
+Line 1 /* Test for a bug where #pragma was throwing off the __LINE__ count. */
+Line __LINE__ /* Line 2 */
+#pragma Line 3
+Line __LINE__ /* Line 4 */
+#pragma Line 5
+Line __LINE__ /* Line 6 */
diff --git a/src/compiler/glsl/glcpp/tests/141-pragma-and-__LINE__.c.expected b/src/compiler/glsl/glcpp/tests/141-pragma-and-__LINE__.c.expected
new file mode 100644
index 00000000000..330731dc800
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/141-pragma-and-__LINE__.c.expected
@@ -0,0 +1,6 @@
+Line 1
+Line 2
+#pragma Line 3
+Line 4
+#pragma Line 5
+Line 6
diff --git a/src/compiler/glsl/glcpp/tests/142-defined-within-macro.c b/src/compiler/glsl/glcpp/tests/142-defined-within-macro.c
new file mode 100644
index 00000000000..b60c04232a6
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/142-defined-within-macro.c
@@ -0,0 +1,94 @@
+/* Macro using defined with a hard-coded identifier (no parentheses) */
+#define is_foo_defined defined /*...*/ foo
+#undef foo
+#if is_foo_defined
+failure
+#else
+success
+#endif
+#define foo
+#if is_foo_defined
+success
+#else
+failure
+#endif
+
+/* Macro using defined with a hard-coded identifier within parentheses */
+#define is_foo_defined_parens defined /*...*/ ( /*...*/ foo /*...*/ ) //
+#define foo
+#if is_foo_defined_parens
+success
+#else
+failure
+#endif
+#undef foo
+#if is_foo_defined_parens
+failure
+#else
+success
+#endif
+
+/* Macro using defined with an argument identifier (no parentheses) */
+#define is_defined(arg) defined /*...*/ arg
+#define foo bar
+#undef bar
+#if is_defined(foo)
+failure
+#else
+success
+#endif
+#define bar bar
+#if is_defined(foo)
+success
+#else
+failure
+#endif
+
+/* Macro using defined with an argument identifier within parentheses */
+#define is_defined_parens(arg) defined /*...*/ ( /*...*/ arg /*...*/ ) //
+#define foo bar
+#define bar bar
+#if is_defined_parens(foo)
+success
+#else
+failure
+#endif
+#undef bar
+#if is_defined_parens(foo)
+failure
+#else
+success
+#endif
+
+/* Multiple levels of macro resulting in defined */
+#define X defined A && Y
+#define Y defined B && Z
+#define Z defined C
+#define A
+#define B
+#define C
+#if X
+success
+#else
+failure
+#endif
+#undef A
+#if X
+failure
+#else
+success
+#endif
+#define A
+#undef B
+#if X
+failure
+#else
+success
+#endif
+#define B
+#undef C
+#if X
+failure
+#else
+success
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/142-defined-within-macro.c.expected b/src/compiler/glsl/glcpp/tests/142-defined-within-macro.c.expected
new file mode 100644
index 00000000000..4eca90bc3db
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/142-defined-within-macro.c.expected
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+success
+
+
+
+success
+
+
+
+
+
+
+
+
+success
+
+
+
+
+
+
+
+success
+
+
+
+
+
+
+
+
+
+success
+
+
+
+success
+
+
+
+
+
+
+
+
+
+success
+
+
+
+
+
+
+
+success
+
+
+
+
+
+
+
+
+
+
+success
+
+
+
+
+
+
+
+success
+
+
+
+
+
+
+success
+
+
+
+
+
+
+success
+
diff --git a/src/compiler/glsl/glcpp/tests/143-multiple-else.c b/src/compiler/glsl/glcpp/tests/143-multiple-else.c
new file mode 100644
index 00000000000..62ad49cf7bb
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/143-multiple-else.c
@@ -0,0 +1,6 @@
+#if 0
+#else
+int foo;
+#else
+int bar;
+#endif
diff --git a/src/compiler/glsl/glcpp/tests/143-multiple-else.c.expected b/src/compiler/glsl/glcpp/tests/143-multiple-else.c.expected
new file mode 100644
index 00000000000..00b3328c835
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/143-multiple-else.c.expected
@@ -0,0 +1,7 @@
+0:4(1): preprocessor error: multiple #else
+
+
+int foo;
+
+int bar;
+
diff --git a/src/compiler/glsl/glcpp/tests/glcpp-test b/src/compiler/glsl/glcpp/tests/glcpp-test
new file mode 100755
index 00000000000..3945ee4f6ce
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/glcpp-test
@@ -0,0 +1,110 @@
+#!/bin/sh
+
+if [ ! -z "$srcdir" ]; then
+ testdir=$srcdir/glsl/glcpp/tests
+ outdir=`pwd`/glsl/glcpp/tests
+ glcpp=`pwd`/glsl/glcpp/glcpp
+else
+ testdir=.
+ outdir=.
+ glcpp=../glcpp
+fi
+
+trap 'rm $test.valgrind-errors; exit 1' INT QUIT
+
+usage ()
+{
+ cat <<EOF
+Usage: glcpp [options...]
+
+Run the test suite for mesa's GLSL pre-processor.
+
+Valid options include:
+
+ --testdir=<DIR> Use tests in the given <DIR> (default is ".")
+ --valgrind Run the test suite a second time under valgrind
+EOF
+}
+
+test_specific_args ()
+{
+ test="$1"
+
+ tr "\r" "\n" < "$test" | grep 'glcpp-args:' | sed -e 's,^.*glcpp-args: *,,'
+}
+
+# Parse command-line options
+for option; do
+ case "${option}" in
+ "--help")
+ usage
+ exit 0
+ ;;
+ "--valgrind")
+ do_valgrind=yes
+ ;;
+ "--testdir="*)
+ testdir="${option#--testdir=}"
+ outdir="${outdir}/${option#--testdir=}"
+ ;;
+ *)
+ echo "Unrecognized option: $option" >&2
+ echo >&2
+ usage
+ exit 1
+ ;;
+ esac
+done
+
+total=0
+pass=0
+clean=0
+
+mkdir -p $outdir
+
+echo "====== Testing for correctness ======"
+for test in $testdir/*.c; do
+ out=$outdir/${test##*/}.out
+
+ printf "Testing $test... > $out ($test.expected) "
+ $glcpp $(test_specific_args $test) < $test > $out 2>&1
+ total=$((total+1))
+ if cmp $test.expected $out >/dev/null 2>&1; then
+ echo "PASS"
+ pass=$((pass+1))
+ else
+ echo "FAIL"
+ diff -u $test.expected $out
+ fi
+done
+
+echo ""
+echo "$pass/$total tests returned correct results"
+echo ""
+
+if [ "$do_valgrind" = "yes" ]; then
+ echo "====== Testing for valgrind cleanliness ======"
+ for test in $testdir/*.c; do
+ printf "Testing $test with valgrind..."
+ valgrind --error-exitcode=31 --log-file=$test.valgrind-errors $glcpp $(test_specific_args $test) < $test >/dev/null 2>&1
+ if [ "$?" = "31" ]; then
+ echo "ERRORS"
+ cat $test.valgrind-errors
+ else
+ echo "CLEAN"
+ clean=$((clean+1))
+ rm $test.valgrind-errors
+ fi
+ done
+
+ echo ""
+ echo "$pass/$total tests returned correct results"
+ echo "$clean/$total tests are valgrind-clean"
+fi
+
+if [ "$pass" = "$total" ] && [ "$do_valgrind" != "yes" ] || [ "$pass" = "$total" ]; then
+ exit 0
+else
+ exit 1
+fi
+
diff --git a/src/compiler/glsl/glcpp/tests/glcpp-test-cr-lf b/src/compiler/glsl/glcpp/tests/glcpp-test-cr-lf
new file mode 100755
index 00000000000..c75370f48c3
--- /dev/null
+++ b/src/compiler/glsl/glcpp/tests/glcpp-test-cr-lf
@@ -0,0 +1,141 @@
+#!/bin/sh
+
+# The build system runs this test from a different working directory, and may
+# be in a build directory entirely separate from the source. So if the
+# "srcdir" variable is set, we must use it to locate the test files and the
+# glcpp-test script.
+
+if [ ! -z "$srcdir" ]; then
+ testdir="$srcdir/glsl/glcpp/tests"
+ glcpp_test="$srcdir/glsl/glcpp/tests/glcpp-test"
+else
+ testdir=.
+ glcpp_test=./glcpp-test
+fi
+
+total=0
+pass=0
+
+# This supports a pipe that doesn't destroy the exit status of first command
+#
+# http://unix.stackexchange.com/questions/14270/get-exit-status-of-process-thats-piped-to-another
+stdintoexitstatus() {
+ read exitstatus
+ return $exitstatus
+}
+
+run_test ()
+{
+ cmd="$1"
+
+ total=$((total+1))
+
+ if [ "$VERBOSE" = "yes" ]; then
+ if $cmd; then
+ echo "PASS"
+ pass=$((pass+1))
+ else
+ echo "FAIL"
+ fi
+ else
+ # This is "$cmd | tail -2" but with the exit status of "$cmd" not "tail -2"
+ if (((($cmd; echo $? >&3) | tail -2 | head -1 >&4) 3>&1) | stdintoexitstatus) 4>&1; then
+ echo "PASS"
+ pass=$((pass+1))
+ else
+ echo "FAIL"
+ fi
+ fi
+}
+
+usage ()
+{
+ cat <<EOF
+Usage: glcpp-cr-lf [options...]
+
+Run the entire glcpp-test suite several times, each time with each source
+file transformed to use a non-standard line-termination character. Each
+entire run with a different line-termination character is considered a
+single test.
+
+Valid options include:
+
+ -v|--verbose Print all output from the various sub-tests
+EOF
+}
+
+# Parse command-line options
+for option; do
+ case "${option}" in
+ -v|--verbose)
+ VERBOSE=yes;
+ ;;
+ *)
+ echo "Unrecognized option: $option" >&2
+ echo >&2
+ usage
+ exit 1
+ ;;
+ esac
+done
+
+# All tests depend on the .out files being present. So first do a
+# normal run of the test suite, (silently) just to create the .out
+# files as a side effect.
+rm -rf ./subtest-lf
+mkdir subtest-lf
+for file in "$testdir"/*.c; do
+ base=$(basename "$file")
+ cp "$file" subtest-lf
+done
+
+${glcpp_test} --testdir=subtest-lf >/dev/null 2>&1
+
+echo "===== Testing with \\\\r line terminators (old Mac format) ====="
+
+# Prepare test files with '\r' instead of '\n'
+rm -rf ./subtest-cr
+mkdir subtest-cr
+for file in "$testdir"/*.c; do
+ base=$(basename "$file")
+ tr "\n" "\r" < "$file" > subtest-cr/"$base"
+ cp `pwd`/glsl/glcpp/tests/subtest-lf/"$base".out subtest-cr/"$base".expected
+done
+
+run_test "${glcpp_test} --testdir=subtest-cr"
+
+echo "===== Testing with \\\\r\\\\n line terminators (DOS format) ====="
+
+# Prepare test files with '\r\n' instead of '\n'
+rm -rf ./subtest-cr-lf
+mkdir subtest-cr-lf
+for file in "$testdir"/*.c; do
+ base=$(basename "$file")
+ sed -e 's/$/ /' < "$file" > subtest-cr-lf/"$base"
+ cp `pwd`/glsl/glcpp/tests/subtest-lf/"$base".out subtest-cr-lf/"$base".expected
+done
+
+run_test "${glcpp_test} --testdir=subtest-cr-lf"
+
+echo "===== Testing with \\\\n\\\\r (bizarre, but allowed by GLSL spec.) ====="
+
+# Prepare test files with '\n\r' instead of '\n'
+rm -rf ./subtest-lf-cr
+mkdir subtest-lf-cr
+for file in "$testdir"/*.c; do
+ base=$(basename "$file")
+ sed -e 's/$/ /' < "$file" | tr "\n\r" "\r\n" > subtest-lf-cr/"$base"
+ cp `pwd`/glsl/glcpp/tests/subtest-lf/"$base".out subtest-lf-cr/"$base".expected
+done
+
+run_test "${glcpp_test} --testdir=subtest-lf-cr"
+
+echo ""
+echo "$pass/$total tests returned correct results"
+echo ""
+
+if [ "$pass" = "$total" ]; then
+ exit 0
+else
+ exit 1
+fi