C, Ocean Edition I

Annex A. Grammar

Annex
A
ISO C99 mapping
Annex A
Status
Normative summary

A.0 About This Annex

This annex collects the complete grammar of Ocean Edition I. It repeats, in one place, the productions that appear throughout clause 6, and it is the copy an implementation is expected to transcribe. Where a grammar fragment inside a language clause disagrees with this annex, this annex wins.

The notation is described in clause 0.6. An element followed by opt is optional. Repetition is written by recursion.

The grammar is ambiguous without declaration information, because a typedef name and an ordinary identifier are spelled the same way. Resolving that requires the parser to track declarations. See clause 6.7.7.


A.1 Lexical Grammar

A.1.1 Tokens

token:
	keyword
	identifier
	constant
	string-literal
	punctuator
preprocessing-token:
	header-name
	identifier
	pp-number
	character-constant
	string-literal
	punctuator
	each non-white-space character that cannot be one of the above

A.1.2 Keywords

keyword: one of
	bool      break     case      char      const
	continue  default   do        double    else
	enum      extern    false     float     for
	goto      if        inline    int       long
	namespace null      NULL      restrict  return
	short     signed    sizeof    static    struct
	switch    true      typedef   union     unsigned
	void      volatile  while

The identifiers auto, register, and _Bool are reserved and are not keywords. See clause 6.4.1.1.

A.1.3 Identifiers

identifier:
	identifier-nondigit
	identifier identifier-nondigit
	identifier digit

identifier-nondigit:
	nondigit
	universal-character-name
	other implementation-defined characters

nondigit: one of
	_ a b c d e f g h i j k l m n o p q r s t u v w x y z
	  A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

digit: one of
	0 1 2 3 4 5 6 7 8 9
qualified-identifier:
	:: identifier
	namespace-qualification :: identifier

namespace-qualification:
	namespace-name
	namespace-qualification :: namespace-name

namespace-name:
	identifier

A qualified-identifier is not a token. It is a sequence of tokens, defined here so that both the lexical grammar and the phrase structure grammar can refer to it. See clause 6.5.1.1.

A.1.4 Universal Character Names

universal-character-name:
	\u hex-quad
	\U hex-quad hex-quad

hex-quad:
	hexadecimal-digit hexadecimal-digit hexadecimal-digit hexadecimal-digit

A.1.5 Constants

constant:
	integer-constant
	floating-constant
	enumeration-constant
	character-constant
	boolean-constant
	null-constant
integer-constant:
	decimal-constant integer-suffix-opt
	octal-constant integer-suffix-opt
	hexadecimal-constant integer-suffix-opt

decimal-constant:
	nonzero-digit
	decimal-constant digit

octal-constant:
	0
	octal-constant octal-digit

hexadecimal-constant:
	hexadecimal-prefix hexadecimal-digit
	hexadecimal-constant hexadecimal-digit

hexadecimal-prefix: one of
	0x 0X

nonzero-digit: one of
	1 2 3 4 5 6 7 8 9

octal-digit: one of
	0 1 2 3 4 5 6 7

hexadecimal-digit: one of
	0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F

integer-suffix:
	unsigned-suffix long-suffix-opt
	unsigned-suffix long-long-suffix
	long-suffix unsigned-suffix-opt
	long-long-suffix unsigned-suffix-opt

unsigned-suffix: one of
	u U

long-suffix: one of
	l L

long-long-suffix: one of
	ll LL
floating-constant:
	decimal-floating-constant
	hexadecimal-floating-constant

decimal-floating-constant:
	fractional-constant exponent-part-opt floating-suffix-opt
	digit-sequence exponent-part floating-suffix-opt

hexadecimal-floating-constant:
	hexadecimal-prefix hexadecimal-fractional-constant
		binary-exponent-part floating-suffix-opt
	hexadecimal-prefix hexadecimal-digit-sequence
		binary-exponent-part floating-suffix-opt

fractional-constant:
	digit-sequence-opt . digit-sequence
	digit-sequence .

exponent-part:
	e sign-opt digit-sequence
	E sign-opt digit-sequence

sign: one of
	+ -

digit-sequence:
	digit
	digit-sequence digit

hexadecimal-fractional-constant:
	hexadecimal-digit-sequence-opt . hexadecimal-digit-sequence
	hexadecimal-digit-sequence .

binary-exponent-part:
	p sign-opt digit-sequence
	P sign-opt digit-sequence

hexadecimal-digit-sequence:
	hexadecimal-digit
	hexadecimal-digit-sequence hexadecimal-digit

floating-suffix: one of
	f l F L
enumeration-constant:
	identifier
	qualified-identifier
boolean-constant: one of
	true false
null-constant: one of
	null NULL
character-constant:
	' c-char-sequence '
	L' c-char-sequence '

c-char-sequence:
	c-char

c-char:
	any member of the source character set except ' , \ , or a new-line
	escape-sequence

A c-char-sequence contains exactly one c-char. Multi-character constants are not part of this edition. See clause 6.4.4.4.

escape-sequence:
	simple-escape-sequence
	octal-escape-sequence
	hexadecimal-escape-sequence
	universal-character-name

simple-escape-sequence: one of
	\' \" \? \\ \a \b \f \n \r \t \v

octal-escape-sequence:
	\ octal-digit
	\ octal-digit octal-digit
	\ octal-digit octal-digit octal-digit

hexadecimal-escape-sequence:
	\x hexadecimal-digit
	hexadecimal-escape-sequence hexadecimal-digit

A.1.6 String Literals

string-literal:
	" s-char-sequence-opt "
	L" s-char-sequence-opt "

s-char-sequence:
	s-char
	s-char-sequence s-char

s-char:
	any member of the source character set except " , \ , or a new-line
	escape-sequence

A.1.7 Punctuators

punctuator: one of
	[  ]  (  )  {  }  .  ->
	++ -- &  *  +  -  ~  !
	/  %  << >> <  >  <= >= == != ^ | && ||
	?  :  :: ;  ...
	=  *= /= %= += -= <<= >>= &= ^= |=
	,  #  ##

Digraph spellings are not part of this edition. See clause 5.2.1.1.

A.1.8 Header Names

header-name:
	< h-char-sequence >
	" q-char-sequence "

h-char-sequence:
	h-char
	h-char-sequence h-char

h-char:
	any member of the source character set except a new-line or >

q-char-sequence:
	q-char
	q-char-sequence q-char

q-char:
	any member of the source character set except a new-line or "

A.1.9 Preprocessing Numbers

pp-number:
	digit
	. digit
	pp-number digit
	pp-number identifier-nondigit
	pp-number e sign
	pp-number E sign
	pp-number p sign
	pp-number P sign
	pp-number .

A.2 Phrase Structure Grammar

A.2.1 Expressions

primary-expression:
	identifier
	qualified-identifier
	constant
	string-literal
	( expression )

qualified-identifier is defined in clause A.1.3, because it is built from identifiers and a punctuator and is referred to by both the lexical and the phrase structure grammar.

postfix-expression:
	primary-expression
	postfix-expression [ expression ]
	postfix-expression ( argument-expression-list-opt )
	postfix-expression . identifier
	postfix-expression -> identifier
	postfix-expression ++
	postfix-expression --
	( type-name ) { initializer-list }
	( type-name ) { initializer-list , }

argument-expression-list:
	assignment-expression
	argument-expression-list , assignment-expression
unary-expression:
	postfix-expression
	++ unary-expression
	-- unary-expression
	unary-operator cast-expression
	sizeof unary-expression
	sizeof ( type-name )

unary-operator: one of
	& * + - ~ !
cast-expression:
	unary-expression
	( type-name ) cast-expression
multiplicative-expression:
	cast-expression
	multiplicative-expression * cast-expression
	multiplicative-expression / cast-expression
	multiplicative-expression % cast-expression

additive-expression:
	multiplicative-expression
	additive-expression + multiplicative-expression
	additive-expression - multiplicative-expression

shift-expression:
	additive-expression
	shift-expression << additive-expression
	shift-expression >> additive-expression

relational-expression:
	shift-expression
	relational-expression < shift-expression
	relational-expression > shift-expression
	relational-expression <= shift-expression
	relational-expression >= shift-expression

equality-expression:
	relational-expression
	equality-expression == relational-expression
	equality-expression != relational-expression

AND-expression:
	equality-expression
	AND-expression & equality-expression

exclusive-OR-expression:
	AND-expression
	exclusive-OR-expression ^ AND-expression

inclusive-OR-expression:
	exclusive-OR-expression
	inclusive-OR-expression | exclusive-OR-expression

logical-AND-expression:
	inclusive-OR-expression
	logical-AND-expression && inclusive-OR-expression

logical-OR-expression:
	logical-AND-expression
	logical-OR-expression || logical-AND-expression

conditional-expression:
	logical-OR-expression
	logical-OR-expression ? expression : conditional-expression
assignment-expression:
	conditional-expression
	unary-expression assignment-operator assignment-expression

assignment-operator: one of
	= *= /= %= += -= <<= >>= &= ^= |=
expression:
	assignment-expression
	expression , assignment-expression

constant-expression:
	conditional-expression

A.2.2 Declarations

declaration:
	declaration-specifiers init-declarator-list-opt ;

declaration-specifiers:
	storage-class-specifier-opt type-qualifier-list-opt
		function-specifier-opt type-specifier

init-declarator-list:
	init-declarator
	init-declarator-list , init-declarator

init-declarator:
	declarator
	declarator = initializer

The order of components in declaration-specifiers is fixed. See clause 6.7.8.

storage-class-specifier:
	typedef
	extern
	static
type-specifier:
	void
	bool
	char
	signed char
	unsigned char
	short
	unsigned short
	int
	unsigned int
	long
	unsigned long
	long long
	unsigned long long
	float
	double
	long double
	struct-or-union-specifier
	enum-specifier
	typedef-name

These are the canonical spellings, and they are the only spellings. See clause 6.7.2.1.

struct-or-union-specifier:
	struct-or-union identifier-opt { struct-declaration-list }
	struct-or-union identifier
	struct-or-union qualified-identifier

struct-or-union:
	struct
	union

struct-declaration-list:
	struct-declaration
	struct-declaration-list struct-declaration

struct-declaration:
	specifier-qualifier-list struct-declarator-list ;

specifier-qualifier-list:
	type-qualifier-list-opt type-specifier

struct-declarator-list:
	struct-declarator
	struct-declarator-list , struct-declarator

struct-declarator:
	declarator
	declarator-opt : constant-expression
enum-specifier:
	enum identifier-opt { enumerator-list }
	enum identifier-opt { enumerator-list , }
	enum identifier
	enum qualified-identifier

enumerator-list:
	enumerator
	enumerator-list , enumerator

enumerator:
	enumeration-constant
	enumeration-constant = constant-expression
type-qualifier:
	const
	volatile
	restrict

type-qualifier-list:
	type-qualifier
	type-qualifier-list type-qualifier
function-specifier:
	inline

inline shall appear only together with static. See clause 6.7.4.

declarator:
	pointer-opt direct-declarator

direct-declarator:
	identifier
	( declarator )
	direct-declarator [ constant-expression-opt ]
	direct-declarator ( parameter-type-list )

pointer:
	* type-qualifier-list-opt
	* type-qualifier-list-opt pointer

parameter-type-list:
	void
	parameter-list
	parameter-list , ...

parameter-list:
	parameter-declaration
	parameter-list , parameter-declaration

parameter-declaration:
	declaration-specifiers declarator
	declaration-specifiers abstract-declarator-opt

A direct-declarator with omitted constant-expression is permitted only for a definition with an initializer and for a flexible array member. Qualifiers and static do not appear inside array brackets. There is no identifier-list production, because old-style function definitions do not exist. See clause 6.7.5.

type-name:
	specifier-qualifier-list abstract-declarator-opt

abstract-declarator:
	pointer
	pointer-opt direct-abstract-declarator

direct-abstract-declarator:
	( abstract-declarator )
	direct-abstract-declarator-opt [ constant-expression-opt ]
	direct-abstract-declarator-opt ( parameter-type-list-opt )
typedef-name:
	identifier
	qualified-identifier
initializer:
	assignment-expression
	{ initializer-list }
	{ initializer-list , }

initializer-list:
	designation-opt initializer
	initializer-list , designation-opt initializer

designation:
	designator-list =

designator-list:
	designator
	designator-list designator

designator:
	[ constant-expression ]
	. identifier

A.2.3 Statements

statement:
	labeled-statement
	compound-statement
	expression-statement
	selection-statement
	iteration-statement
	jump-statement

labeled-statement:
	identifier : statement
	case constant-expression : statement
	default : statement

compound-statement:
	{ block-item-list-opt }

block-item-list:
	block-item
	block-item-list block-item

block-item:
	declaration
	statement

expression-statement:
	expression-opt ;

selection-statement:
	if ( expression ) statement
	if ( expression ) statement else statement
	switch ( expression ) statement

iteration-statement:
	while ( expression ) statement
	do statement while ( expression ) ;
	for ( expression-opt ; expression-opt ; expression-opt ) statement
	for ( declaration expression-opt ; expression-opt ) statement

jump-statement:
	goto identifier ;
	continue ;
	break ;
	return expression-opt ;

A.2.4 External Definitions

translation-unit:
	external-declaration
	translation-unit external-declaration

external-declaration:
	function-definition
	declaration
	namespace-definition

function-definition:
	declaration-specifiers declarator compound-statement

namespace-definition:
	namespace namespace-qualification { external-declaration-list-opt }

external-declaration-list:
	external-declaration
	external-declaration-list external-declaration

There is no declaration-list between the declarator and the body. See clause 6.7.5.3.


A.3 Preprocessing Directives

preprocessing-file:
	group-opt

group:
	group-part
	group group-part

group-part:
	if-section
	control-line
	text-line
	# non-directive

if-section:
	if-group elif-groups-opt else-group-opt endif-line

if-group:
	# if constant-expression new-line group-opt
	# ifdef identifier new-line group-opt
	# ifndef identifier new-line group-opt

elif-groups:
	elif-group
	elif-groups elif-group

elif-group:
	# elif constant-expression new-line group-opt

else-group:
	# else new-line group-opt

endif-line:
	# endif new-line

control-line:
	# include pp-tokens new-line
	# define identifier replacement-list new-line
	# define identifier lparen identifier-list-opt ) replacement-list new-line
	# define identifier lparen ... ) replacement-list new-line
	# define identifier lparen identifier-list , ... ) replacement-list new-line
	# undef identifier new-line
	# line pp-tokens new-line
	# error pp-tokens-opt new-line
	# warning pp-tokens-opt new-line
	# pragma pp-tokens-opt new-line
	# namespace string-literal new-line
	# import pp-tokens new-line
	# new-line

text-line:
	pp-tokens-opt new-line

non-directive:
	pp-tokens new-line

lparen:
	a ( character not immediately preceded by white space

replacement-list:
	pp-tokens-opt

pp-tokens:
	preprocessing-token
	pp-tokens preprocessing-token

identifier-list:
	identifier
	identifier-list , identifier

new-line:
	the new-line character

The defined operator and the __has_include operator appear only in the controlling expression of # if and # elif. See clause 6.10.1.


A.4 Productions ISO C99 Has and This Edition Does Not

For readers transcribing a C99 grammar into an Ocean Edition I one, these productions are deleted:

Deleted production Replacement
storage-class-specifier: auto ordinary block-scope declaration
storage-class-specifier: register ordinary declaration
direct-declarator: direct-declarator [ type-qualifier-list-opt assignment-expression-opt ] constant array bounds only
direct-declarator: direct-declarator [ static type-qualifier-list-opt assignment-expression ] write the pointer type
direct-declarator: direct-declarator [ type-qualifier-list static assignment-expression ] write the pointer type
direct-declarator: direct-declarator [ type-qualifier-list-opt * ] variable-length arrays are removed
direct-declarator: direct-declarator ( identifier-list-opt ) prototypes only
function-definition: declaration-specifiers declarator declaration-list compound-statement prototype-style definitions only
type-specifier: _Bool bool, now a keyword
type-specifier: _Complex optional extension
type-specifier: _Imaginary optional extension
digraph punctuators spell the punctuator

And these productions are constrained rather than deleted:

Production Constraint
declaration-specifiers fixed component order, clause 6.7.8
type-specifier canonical spellings only, clause 6.7.2.1
function-specifier: inline only together with static, clause 6.7.4
c-char-sequence exactly one character, clause 6.4.4.4

And these productions are added:

Added production Reason
type-specifier: bool boolean type promoted to the core language, clause 6.2.5.2
constant: boolean-constant true and false promoted to the core language, clause 6.4.4.5
constant: null-constant null and NULL promoted to the core language, clause 6.4.4.6
control-line: # warning pp-tokens-opt new-line clause 6.10.5.1
keyword: namespace namespace definitions, clause 6.7.10
punctuator: :: namespace qualification, clause 6.5.1.1
primary-expression: qualified-identifier clause 6.5.1.1
external-declaration: namespace-definition clause 6.7.10
control-line: # namespace string-literal new-line clause 6.10.10
control-line: # import pp-tokens new-line clause 6.10.11
typedef-name: qualified-identifier qualified typedef names, clause 6.7.7
enumeration-constant: qualified-identifier qualified enumerators, clause 6.7.2.3
struct-or-union-specifier: struct-or-union qualified-identifier qualified tag reference, clause 6.7.2.2
enum-specifier: enum qualified-identifier qualified tag reference, clause 6.7.2.3

The productions in the last block are the only additions this edition makes to the C grammar, and clause 1.5 states the test they had to pass.