summaryrefslogtreecommitdiff
path: root/script/plugins/ffi/c-parser/c99.lua
diff options
context:
space:
mode:
Diffstat (limited to 'script/plugins/ffi/c-parser/c99.lua')
-rw-r--r--script/plugins/ffi/c-parser/c99.lua731
1 files changed, 731 insertions, 0 deletions
diff --git a/script/plugins/ffi/c-parser/c99.lua b/script/plugins/ffi/c-parser/c99.lua
new file mode 100644
index 00000000..9735afa2
--- /dev/null
+++ b/script/plugins/ffi/c-parser/c99.lua
@@ -0,0 +1,731 @@
+-- C99 grammar written in lpeg.re.
+-- Adapted and translated from plain LPeg grammar for C99
+-- written by Wesley Smith https://github.com/Flymir/ceg
+--
+-- Copyright (c) 2009 Wesley Smith
+--
+-- 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 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.
+
+-- Reference used in the original and in this implementation:
+-- http://www.open-std.org/JTC1/SC22/wg14/www/docs/n1124.pdf
+
+local c99 = {}
+
+local re = require("parser.relabel")
+local typed = require("plugins.ffi.c-parser.typed")
+
+local defs = {}
+
+
+c99.tracing = false
+
+defs["trace"] = function(s, i)
+ if c99.tracing then
+ --local location = require("titan-compiler.location")
+ --local line, col = location.get_line_number(s, i)
+ --print("TRACE", line, col, "[[" ..s:sub(i, i+ 256):gsub("\n.*", "") .. "]]")
+ end
+ return true
+end
+
+local typedefs = {}
+
+local function elem(xs, e)
+ for _, x in ipairs(xs) do
+ if e == x then
+ return true
+ end
+ end
+ return false
+end
+
+defs["decl_func"] = typed("string, number, table -> boolean, Decl", function(_, _, decl)
+ typed.set_type(decl, "Decl")
+ return true, decl
+end)
+
+defs["decl_ids"] = typed("string, number, table -> boolean, Decl?", function(_, _, decl)
+ -- store typedef
+ if elem(decl.spec, "typedef") then
+ if not (decl.ids and decl.ids[1] and decl.ids[1].decl) then
+ return true
+ end
+ for _, id in ipairs(decl.ids) do
+ local name = id.decl.name or id.decl.declarator.name
+ if name then
+ typedefs[name] = true
+ end
+ end
+ end
+ typed.set_type(decl, "Decl")
+ return true, decl
+end)
+
+defs["is_typedef"] = function(_, _, id)
+ --print("is " .. id .. " a typedef? " .. tostring(not not typedefs[id]))
+ return typedefs[id], typedefs[id] and id
+end
+
+defs["empty_table"] = function()
+ return true, {}
+end
+
+-- Flatten nested expression tables
+defs["nest_exp"] = typed("string, number, {Exp} -> boolean, Exp", function(_, _, exp)
+ typed.set_type(exp, "Exp")
+ if not exp.op then
+ return true, exp[1]
+ end
+ return true, exp
+end)
+
+-- Primary expression tables
+defs["prim_exp"] = typed("string, number, {string} -> boolean, Exp", function(_, _, exp)
+ typed.set_type(exp, "Exp")
+ return true, exp
+end)
+
+-- Type tables
+defs["type_exp"] = typed("string, number, table -> boolean, Exp", function(_, _, exp)
+ typed.check(exp[1], "Type")
+ typed.set_type(exp, "Exp")
+ return true, exp
+end)
+
+-- Types
+defs["type"] = typed("string, number, table -> boolean, Type", function(_, _, typ)
+ typed.set_type(typ, "Type")
+ return true, typ
+end)
+
+defs["join"] = typed("string, number, {array} -> boolean, array", function(_, _, xss)
+ -- xss[1] .. xss[2]
+ if xss[2] then
+ table.move(xss[2], 1, #xss[2], #xss[1] + 1, xss[1])
+ end
+ return true, xss[1] or {}
+end)
+
+defs["postfix"] = typed("string, number, table -> boolean, table", function(_, _, pf)
+ typed.check(pf[1], "Exp")
+ if pf.postfix ~= "" then
+ pf[1].postfix = pf.postfix
+ end
+ return true, pf[1]
+end)
+
+defs["litstruct"] = typed("string, number, number -> boolean, string", function(_, _, _)
+ return true, "litstruct"
+end)
+
+--==============================================================================
+-- Lexical Rules (used in both preprocessing and language processing)
+--==============================================================================
+
+local lexical_rules = [[--lpeg.re
+
+TRACE <- ({} => trace)
+
+empty <- ("" => empty_table)
+
+--------------------------------------------------------------------------------
+-- Identifiers
+
+IDENTIFIER <- { identifierNondigit (identifierNondigit / [0-9])* } _
+identifierNondigit <- [a-zA-Z_]
+ / universalCharacterName
+
+identifierList <- {| IDENTIFIER ("," _ IDENTIFIER)* |}
+
+--------------------------------------------------------------------------------
+-- Universal Character Names
+
+universalCharacterName <- "\u" hexQuad
+ / "\U" hexQuad hexQuad
+hexQuad <- hexDigit^4
+
+--------------------------------------------------------------------------------
+-- String Literals
+
+STRING_LITERAL <- { ('"' / 'L"') sChar* '"' } _
+
+sChar <- (!["\%nl] .) / escapeSequence
+
+--------------------------------------------------------------------------------
+-- Escape Sequences
+
+escapeSequence <- simpleEscapeSequence
+ / octalEscapeSequence
+ / hexEscapeSequence
+ / universalCharacterName
+
+simpleEscapeSequence <- "\" ['"?\abfnrtv]
+
+octalEscapeSequence <- "\" [0-7] [0-7]^-2
+
+hexEscapeSequence <- "\x" hexDigit+
+
+--------------------------------------------------------------------------------
+-- Constants
+
+INTEGER_CONSTANT <- { ( hexConstant integerSuffix?
+ / octalConstant integerSuffix?
+ / decimalConstant integerSuffix?
+ ) } _
+
+decimalConstant <- [1-9] digit*
+octalConstant <- "0" [0-7]*
+hexConstant <- ("0x" / "0X") hexDigit+
+
+digit <- [0-9]
+hexDigit <- [0-9a-fA-F]
+
+integerSuffix <- unsignedSuffix longLongSuffix
+ / unsignedSuffix longSuffix?
+ / longLongSuffix unsignedSuffix?
+ / longSuffix unsignedSuffix?
+
+unsignedSuffix <- [uU]
+longSuffix <- [lL]
+longLongSuffix <- "ll" / "LL"
+
+FLOATING_CONSTANT <- { ( decimalFloatingConstant
+ / hexFloatingConstant
+ ) } _
+
+decimalFloatingConstant <- fractionalConstant exponentPart? floatingSuffix?
+ / digit+ exponentPart floatingSuffix?
+
+hexFloatingConstant <- ("0x" / "0X" ) ( hexFractionalConstant binaryExponentPart floatingSuffix?
+ / hexDigit+ binaryExponentPart floatingSuffix? )
+
+fractionalConstant <- digit* "." digit+
+ / digit "."
+
+exponentPart <- [eE] [-+]? digit+
+
+hexFractionalConstant <- hexDigit+? "." hexDigit+
+ / hexDigit+ "."
+
+binaryExponentPart <- [pP] digit+
+
+floatingSuffix <- [flFL]
+
+CHARACTER_CONSTANT <- { ("'" / "L'") cChar+ "'" } _
+
+cChar <- (!['\%nl] .) / escapeSequence
+
+enumerationConstant <- IDENTIFIER
+
+]]
+
+local common_expression_rules = [[--lpeg.re
+
+--------------------------------------------------------------------------------
+-- Common Expression Rules
+
+multiplicativeExpression <- {| castExpression ({:op: [*/%] :} _ castExpression )* |} => nest_exp
+additiveExpression <- {| multiplicativeExpression ({:op: [-+] :} _ multiplicativeExpression )* |} => nest_exp
+shiftExpression <- {| additiveExpression ({:op: ("<<" / ">>") :} _ additiveExpression )* |} => nest_exp
+relationalExpression <- {| shiftExpression ({:op: (">=" / "<=" / "<" / ">") :} _ shiftExpression )* |} => nest_exp
+equalityExpression <- {| relationalExpression ({:op: ("==" / "!=") :} _ relationalExpression )* |} => nest_exp
+bandExpression <- {| equalityExpression ({:op: "&" :} _ equalityExpression )* |} => nest_exp
+bxorExpression <- {| bandExpression ({:op: "^" :} _ bandExpression )* |} => nest_exp
+borExpression <- {| bxorExpression ({:op: "|" :} _ bxorExpression )* |} => nest_exp
+andExpression <- {| borExpression ({:op: "&&" :} _ borExpression )* |} => nest_exp
+orExpression <- {| andExpression ({:op: "||" :} _ andExpression )* |} => nest_exp
+conditionalExpression <- {| orExpression ({:op: "?" :} _ expression ":" _ conditionalExpression)? |} => nest_exp
+
+constantExpression <- conditionalExpression
+
+]]
+
+--==============================================================================
+-- Language Rules (Phrase Structure Grammar)
+--==============================================================================
+
+local language_rules = [[--lpeg.re
+
+--------------------------------------------------------------------------------
+-- External Definitions
+
+translationUnit <- %s* {| externalDeclaration* |} "$EOF$"
+
+externalDeclaration <- functionDefinition
+ / declaration
+
+functionDefinition <- {| {:spec: {| declarationSpecifier+ |} :} {:func: declarator :} {:decls: declaration* :} {:code: compoundStatement :} |} => decl_func
+
+--------------------------------------------------------------------------------
+-- Declarations
+
+declaration <- {| gccExtensionSpecifier? {:spec: {| declarationSpecifier+ |} :} ({:ids: initDeclarationList :})? gccExtensionSpecifier* ";" _ |} => decl_ids
+
+declarationSpecifier <- storageClassSpecifier
+ / typeSpecifier
+ / typeQualifier
+ / functionSpecifier
+
+initDeclarationList <- {| initDeclarator ("," _ initDeclarator)* |}
+
+initDeclarator <- {| {:decl: declarator :} ("=" _ {:value: initializer :} )? |}
+
+gccExtensionSpecifier <- "__attribute__" _ "(" _ "(" _ gccAttributeList ")" _ ")" _
+ / gccAsm
+ / clangAsm
+ / "__DARWIN_ALIAS_STARTING_MAC_1060" _ "(" _ clangAsm ")" _
+ / "__AVAILABILITY_INTERNAL" [a-zA-Z0-9_]+ _ ("(" _ STRING_LITERAL ")" _ )?
+
+gccAsm <- "__asm__" _ "(" _ (STRING_LITERAL / ":" _ / expression)+ ")" _
+
+clangAsm <- "__asm" _ "(" _ (STRING_LITERAL / ":" _ / expression)+ ")" _
+
+gccAttributeList <- {| gccAttributeItem ("," _ gccAttributeItem )* |}
+
+gccAttributeItem <- clangAsm
+ / IDENTIFIER ("(" _ (expression ("," _ expression)*)? ")" _)?
+ / ""
+
+storageClassSpecifier <- { "typedef" } _
+ / { "extern" } _
+ / { "static" } _
+ / { "auto" } _
+ / { "register" } _
+
+typeSpecifier <- typedefName
+ / { "void" } _
+ / { "bool" } _
+ / { "char" } _
+ / { "short" } _
+ / { "int" } _
+ / { "long" } _
+ / { "float" } _
+ / { "double" } _
+ / { "signed" } _
+ / { "__signed" } _
+ / { "__signed__" } _
+ / { "unsigned" } _
+ / { "ptrdiff_t" } _
+ / { "size_t" } _
+ / { "ssize_t" } _
+ / { "wchar_t" } _
+ / { "int8_t" } _
+ / { "int16_t" } _
+ / { "int32_t" } _
+ / { "int64_t" } _
+ / { "uint8_t" } _
+ / { "uint16_t" } _
+ / { "uint32_t" } _
+ / { "uint64_t" } _
+ / { "intptr_t" } _
+ / { "uintptr_t" } _
+ / { "__int8" } _
+ / { "__int16" } _
+ / { "__int32" } _
+ / { "__int64" } _
+ / { "_Bool" } _
+ / { "_Complex" } _
+ / { "complex" } _
+ / { "__complex" } _
+ / { "__complex__" } _
+ / { "__ptr32" } _
+ / { "__ptr64" } _
+ / structOrUnionSpecifier
+ / enumSpecifier
+
+typeQualifier <- { "const" } _
+ / { "restrict" } _
+ / { "volatile" } _
+
+functionSpecifier <- { "inline" } _
+
+structOrUnionSpecifier <- {| {:type: structOrUnion :} ({:id: IDENTIFIER :})? "{" _ {:fields: {| structDeclaration+ |} :}? "}" _ |}
+ / {| {:type: structOrUnion :} {:id: IDENTIFIER :} |}
+
+structOrUnion <- { "struct" } _
+ / { "union" } _
+
+anonymousUnion <- {| {:type: {| {:type: { "union" } :} _ "{" _ {:fields: {| structDeclaration+ |} :}? "}" _ |} :} |} ";" _
+
+structDeclaration <- anonymousUnion
+ / {| {:type: {| specifierQualifier+ |} :} {:ids: structDeclaratorList :} |} ";" _
+
+specifierQualifier <- typeSpecifier
+ / typeQualifier
+
+structDeclaratorList <- {| structDeclarator ("," _ structDeclarator)* |}
+
+structDeclarator <- declarator? ":" _ constantExpression
+ / declarator
+
+enumSpecifier <- {| {:type: enum :} ({:id: IDENTIFIER :})? "{" _ {:values: enumeratorList :}? ("," _)? "}" _ |}
+ / {| {:type: enum :} {:id: IDENTIFIER :} |}
+
+enum <- { "enum" } _
+
+enumeratorList <- {| enumerator ("," _ enumerator)* |}
+
+enumerator <- {| {:id: enumerationConstant :} ("=" _ {:value: constantExpression :})? |}
+
+declarator <- {| pointer? directDeclarator |}
+
+directDeclarator <- {:name: IDENTIFIER :} ddRec
+ / "(" _ {:declarator: declarator :} ")" _ ddRec
+ddRec <- "[" _ {| {:idx: typeQualifier* assignmentExpression? :} |} "]" _ ddRec
+ / "[" _ {| {:idx: { "static" } _ typeQualifier* assignmentExpression :} |} "]" _ ddRec
+ / "[" _ {| {:idx: typeQualifier+ { "static" } _ assignmentExpression :} |} "]" _ ddRec
+ / "[" _ {| {:idx: typeQualifier* { "*" } _ :} |} "]" _ ddRec
+ / "(" _ {:params: parameterTypeList / empty :} ")" _ ddRec
+ / "(" _ {:params: identifierList / empty :} ")" _ ddRec
+ / ""
+
+pointer <- {| ({ "*"/"^" } _ typeQualifier*)+ |}
+
+parameterTypeList <- {| parameterList "," _ {| { "..." } |} _ |} => join
+ / parameterList
+
+parameterList <- {| parameterDeclaration ("," _ parameterDeclaration)* |}
+
+parameterDeclaration <- {| {:param: {| {:type: {| declarationSpecifier+ |} :} {:id: (declarator / abstractDeclarator?) :} |} :} |}
+
+typeName <- {| specifierQualifier+ abstractDeclarator? |} => type
+
+abstractDeclarator <- pointer? directAbstractDeclarator
+ / pointer
+
+directAbstractDeclarator <- ("(" _ abstractDeclarator ")" _) directAbstractDeclarator2*
+ / directAbstractDeclarator2+
+directAbstractDeclarator2 <- "[" _ assignmentExpression? "]" _
+ / "[" _ "*" _ "]" _
+ / "(" _ (parameterTypeList / empty) ")" _
+
+typedefName <- IDENTIFIER => is_typedef
+
+initializer <- assignmentExpression
+ / "{" _ initializerList ("," _)? "}" _
+
+initializerList <- {| initializerList2 ("," _ initializerList2)* |}
+initializerList2 <- designation? initializer
+
+designation <- designator+ "=" _
+
+designator <- "[" _ constantExpression "]" _
+ / "." _ IDENTIFIER
+
+--------------------------------------------------------------------------------
+-- Statements
+
+statement <- labeledStatement
+ / compoundStatement
+ / expressionStatement
+ / selectionStatement
+ / iterationStatement
+ / jumpStatement
+ / gccAsm ";" _
+
+labeledStatement <- IDENTIFIER ":" _ statement
+ / "case" _ constantExpression ":" _ statement
+ / "default" _ ":" _ statement
+
+compoundStatement <- "{" _ blockItem+ "}" _
+
+blockItem <- declaration
+ / statement
+
+expressionStatement <- expression? ";" _
+
+selectionStatement <- "if" _ "(" _ expression ")" _ statement "else" _ statement
+ / "if" _ "(" _ expression ")" _ statement
+ / "switch" _ "(" _ expression ")" _ statement
+
+iterationStatement <- "while" _ "(" _ expression ")" _ statement
+ / "do" _ statement "while" _ "(" _ expression ")" _ ";" _
+ / "for" _ "(" _ expression? ";" _ expression? ";" _ expression? ")" _ statement
+ / "for" _ "(" _ declaration expression? ";" _ expression? ")" _ statement
+
+jumpStatement <- "goto" _ IDENTIFIER ";" _
+ / "continue" _ ";" _
+ / "break" _ ";" _
+ / "return" _ expression? ";" _
+
+--------------------------------------------------------------------------------
+-- Advanced Language Expression Rules
+-- (which require type names)
+
+postfixExpression <- {| {:op: {} => litstruct :} "(" _ {:struct: typeName :} ")" _ "{" _ {:vals: initializerList :} ("," _)? "}" _ peRec |} => nest_exp
+ / {| primaryExpression {:postfix: peRec :} |} => postfix
+
+sizeofOrPostfixExpression <- {| {:op: "sizeof" :} _ "(" _ typeName ")" _ |} => type_exp
+ / {| {:op: "sizeof" :} _ unaryExpression |} => nest_exp
+ / postfixExpression
+
+castExpression <- {| "(" _ typeName ")" _ castExpression |} => type_exp
+ / unaryExpression
+
+]]
+
+--==============================================================================
+-- Language Expression Rules
+--==============================================================================
+
+local language_expression_rules = [[--lpeg.re
+
+--------------------------------------------------------------------------------
+-- Language Expression Rules
+-- (rules which differ from preprocessing stage)
+
+expression <- {| assignmentExpression ({:op: "," :} _ assignmentExpression)* |} => nest_exp
+
+constant <- ( FLOATING_CONSTANT
+ / INTEGER_CONSTANT
+ / CHARACTER_CONSTANT
+ / enumerationConstant
+ )
+
+primaryExpression <- {| constant |} => prim_exp
+ / {| IDENTIFIER |} => prim_exp
+ / {| STRING_LITERAL+ |} => prim_exp
+ / "(" _ expression ")" _
+
+peRec <- {| "[" _ {:idx: expression :} "]" _ peRec |}
+ / {| "(" _ {:args: argumentExpressionList / empty :} ")" _ peRec |}
+ / {| "." _ {:dot: IDENTIFIER :} peRec |}
+ / {| "->" _ {:arrow: IDENTIFIER :} peRec |}
+ / {| "++" _ peRec |}
+ / {| "--" _ peRec |}
+ / ""
+
+argumentExpressionList <- {| assignmentExpression ("," _ assignmentExpression)* |}
+
+unaryExpression <- {| {:op: prefixOp :} unaryExpression |} => nest_exp
+ / {| {:op: unaryOperator :} castExpression |} => nest_exp
+ / sizeofOrPostfixExpression
+
+prefixOp <- { "++" } _
+ / { "--" } _
+
+unaryOperator <- { [-+~!*&] } _
+
+assignmentExpression <- unaryExpression assignmentOperator assignmentExpression
+ / conditionalExpression
+
+assignmentOperator <- "=" _
+ / "*=" _
+ / "/=" _
+ / "%=" _
+ / "+=" _
+ / "-=" _
+ / "<<=" _
+ / ">>=" _
+ / "&=" _
+ / "^=" _
+ / "|=" _
+
+--------------------------------------------------------------------------------
+-- Language whitespace
+
+_ <- %s+
+S <- %s+
+
+]]
+
+local simplified_language_expression_rules = [[--lpeg.re
+
+--------------------------------------------------------------------------------
+-- Simplified Language Expression Rules
+-- (versions that do not require knowledge of type names)
+
+postfixExpression <- {| primaryExpression {:postfix: peRec :} |} => postfix
+
+sizeofOrPostfixExpression <- postfixExpression
+
+castExpression <- unaryExpression
+
+]]
+
+--==============================================================================
+-- Preprocessing Rules
+--==============================================================================
+
+local preprocessing_rules = [[--lpeg.re
+
+preprocessingLine <- _ ( "#" _ directive _
+ / "#" _ preprocessingTokenList? {| _ |} -- non-directive, ignore
+ / preprocessingTokenList
+ / empty
+ )
+
+preprocessingTokenList <- {| (preprocessingToken _)+ |}
+
+directive <- {| {:directive: "if" :} S {:exp: preprocessingTokenList :} |}
+ / {| {:directive: "ifdef" :} S {:id: IDENTIFIER :} |}
+ / {| {:directive: "ifndef" :} S {:id: IDENTIFIER :} |}
+ / {| {:directive: "elif" :} S {:exp: preprocessingTokenList :} |}
+ / {| {:directive: "else" :} |}
+ / {| {:directive: "endif" :} |}
+ / {| {:directive: "include" :} S {:exp: headerName :} |}
+ / {| {:directive: "define" :} S {:id: IDENTIFIER :} "(" _ {:args: defineArgList :} _ ")" _ {:repl: replacementList :} |}
+ / {| {:directive: "define" :} S {:id: IDENTIFIER :} _ {:repl: replacementList :} |}
+ / {| {:directive: "undef" :} S {:id: IDENTIFIER :} |}
+ / {| {:directive: "line" :} S {:line: preprocessingTokenList :} |}
+ / {| {:directive: "error" :} S {:error: preprocessingTokenList / empty :} |}
+ / {| {:directive: "error" :} |}
+ / {| {:directive: "pragma" :} S {:pragma: preprocessingTokenList / empty :} |}
+ / gccDirective
+ / ""
+
+gccDirective <- {| {:directive: "include_next" :} S {:exp: headerName :} |}
+ / {| {:directive: "warning" :} S {:exp: preprocessingTokenList / empty :} |}
+
+defineArgList <- {| { "..." } |}
+ / {| identifierList _ "," _ {| { "..." } |} |} => join
+ / identifierList
+ / empty
+
+replacementList <- {| (preprocessingToken _)* |}
+
+preprocessingToken <- preprocessingNumber
+ / CHARACTER_CONSTANT
+ / STRING_LITERAL
+ / punctuator
+ / IDENTIFIER
+
+headerName <- {| {:mode: "<" -> "system" :} { (![%nl>] .)+ } ">" |}
+ / {| {:mode: '"' -> "quote" :} { (![%nl"] .)+ } '"' |}
+ / {| IDENTIFIER |} -- macro
+
+preprocessingNumber <- { ("."? digit) ( digit
+ / [eEpP] [-+]
+ / identifierNondigit
+ / "."
+ )* }
+
+punctuator <- { digraphs / '...' / '<<=' / '>>=' /
+ '##' / '<<' / '>>' / '->' / '++' / '--' / '&&' / '||' / '<=' / '>=' /
+ '==' / '!=' / '*=' / '/=' / '%=' / '+=' / '-=' / '&=' / '^=' / '|=' /
+ '#' / '[' / ']' / '(' / ')' / '{' / '}' / '.' / '&' /
+ '*' / '+' / '-' / '~' / '!' / '/' / '%' / '<' / '>' /
+ '^' / '|' / '?' / ':' / ';' / ',' / '=' }
+
+digraphs <- '%:%:' -> "##"
+ / '%:' -> "#"
+ / '<:' -> "["
+ / ':>' -> "]"
+ / '<%' -> "{"
+ / '%>' -> "}"
+
+--------------------------------------------------------------------------------
+-- Preprocessing whitespace
+
+_ <- %s*
+S <- %s+
+
+]]
+
+--==============================================================================
+-- Preprocessing Expression Rules
+--==============================================================================
+
+local preprocessing_expression_rules = [[--lpeg.re
+
+--------------------------------------------------------------------------------
+-- Preprocessing Expression Rules
+-- (rules which differ from language processing stage)
+
+expression <- constantExpression
+
+constant <- FLOATING_CONSTANT
+ / INTEGER_CONSTANT
+ / CHARACTER_CONSTANT
+
+primaryExpression <- {| IDENTIFIER |} => prim_exp
+ / {| constant |} => prim_exp
+ / "(" _ expression _ ")" _
+
+postfixExpression <- primaryExpression peRec
+peRec <- "(" _ (argumentExpressionList / empty) ")" _ peRec
+ / ""
+
+argumentExpressionList <- {| expression ("," _ expression )* |}
+
+unaryExpression <- {| {:op: unaryOperator :} unaryExpression |} => nest_exp
+ / primaryExpression
+
+unaryOperator <- { [-+~!] } _
+ / { "defined" } _
+
+castExpression <- unaryExpression
+
+--------------------------------------------------------------------------------
+-- Preprocessing expression whitespace
+
+_ <- %s*
+S <- %s+
+
+]]
+
+local preprocessing_grammar = re.compile(
+ preprocessing_rules ..
+ lexical_rules, defs)
+
+local preprocessing_expression_grammar = re.compile(
+ preprocessing_expression_rules ..
+ lexical_rules ..
+ common_expression_rules, defs)
+
+local language_expression_grammar = re.compile(
+ language_expression_rules ..
+ simplified_language_expression_rules ..
+ lexical_rules ..
+ common_expression_rules, defs)
+
+local language_grammar = re.compile(
+ language_rules ..
+ language_expression_rules ..
+ lexical_rules ..
+ common_expression_rules, defs)
+
+local function match(grammar, subject)
+ local res, err, pos = grammar:match(subject)
+ if res == nil then
+ local l, c = re.calcline(subject, pos)
+ local fragment = subject:sub(pos, pos+20)
+ return res, err, l, c, fragment
+ end
+ return res
+end
+
+function c99.match_language_grammar(subject)
+ typedefs = {}
+ return match(language_grammar, subject)
+end
+
+function c99.match_language_expression_grammar(subject)
+ return match(language_expression_grammar, subject)
+end
+
+function c99.match_preprocessing_grammar(subject)
+ return match(preprocessing_grammar, subject)
+end
+
+function c99.match_preprocessing_expression_grammar(subject)
+ return match(preprocessing_expression_grammar, subject)
+end
+
+return c99