Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
2764 lines (2476 sloc) 70.1 KB
/*
* PUBLIC DOMAIN PCCTS-BASED C++ GRAMMAR (cplusplus.g, stat.g, expr.g)
*
* Authors: Sumana Srinivasan, NeXT Inc.; sumana_srinivasan@next.com
* Terence Parr, Parr Research Corporation; parrt@parr-research.com
* Russell Quong, Purdue University; quong@ecn.purdue.edu
*
* VERSION 1.2
*
* SOFTWARE RIGHTS
*
* This file is a part of the ANTLR-based C++ grammar and is free
* software. We do not reserve any LEGAL rights to its use or
* distribution, but you may NOT claim ownership or authorship of this
* grammar or support code. An individual or company may otherwise do
* whatever they wish with the grammar distributed herewith including the
* incorporation of the grammar or the output generated by ANTLR into
* commerical software. You may redistribute in source or binary form
* without payment of royalties to us as long as this header remains
* in all source distributions.
*
* We encourage users to develop parsers/tools using this grammar.
* In return, we ask that credit is given to us for developing this
* grammar. By "credit", we mean that if you incorporate our grammar or
* the generated code into one of your programs (commercial product,
* research project, or otherwise) that you acknowledge this fact in the
* documentation, research report, etc.... In addition, you should say nice
* things about us at every opportunity.
*
* As long as these guidelines are kept, we expect to continue enhancing
* this grammar. Feel free to send us enhancements, fixes, bug reports,
* suggestions, or general words of encouragement at parrt@parr-research.com.
*
* NeXT Computer Inc.
* 900 Chesapeake Dr.
* Redwood City, CA 94555
* 12/02/1994
*
* Restructured for public consumption by Terence Parr late February, 1995.
*
* DISCLAIMER: we make no guarantees that this grammar works, makes sense,
* or can be used to do anything useful.
*/
/* 2001-2002
* Version 1.0
* This C++ grammar file has been converted from PCCTS to run under
* ANTLR to generate lexer and parser in C++ code by
* Jianguo Zuo and David Wigg at
* The Centre for Systems and Software Engineering
* London South Bank University
* London, UK.
*
*/
/* 2003
* Version 2.0 was published by David Wigg in September 2003
*/
/* 2004
* Version 3.0 July 2004
* This is version 3.0 of the C++ grammar definition for ANTLR to
* generate lexer and parser in C++ code updated by
* David Wigg at
* The Centre for Systems and Software Engineering
* London South Bank University
* London, UK.
*/
/* 2005
* Version 3.1 November 2005
* Updated by David Wigg at London South Bank University
*
*/
/* 2007
* Version 3.2 November 2007
* Updated by David Wigg at London South Bank University
*
* wiggjd@bcs.ac.uk
* blackse@lsbu.ac.uk
*
* See MyReadMe.txt for further information
*
* This file is best viewed in courier font with tabs set to 4 spaces
*/
/* -- 2010 --
* Version 4.0.1 August 2010
* Modified and reworked to compile with ANTLR 3.2
* by Ramin Zaghi
*
* Please note that this is the first public release
* for ANTLR 3.2; This does not comiple with any older
* versions of ANTLR. This may also have some missing
* features compared to the 2007 update by David Wigg.
* I am publishing this work only to make this first
* ANTLR 3.2 update available to the community
* however if you are interested in a more complete
* work please take a look at David's 2007 update.
*
* I emphasize that this new update needs more work
* and can be restructured to make it more developer
* friendly. The project file is a MSVS2008 project
* file and it only includes a "Debug" configuration.
*
* You may send your comments to < antlr3_cpp_parser@taggedprogramming.com >
*
*/
grammar CPP_grammar_;
options
{
language = C;
}
tokens {
OPERATOR = 'operator';
}
@parser::header
{
extern "C++"
{
#include "header_file.h"
}
//typedef CPP_grammar_Parser_function_specifier_return FS_ret_t;
//typedef CPP_grammar_Parser_type_specifier_return TS_ret_t;
}
@parser::members
{
extern "C++"
{
#include "members_file.h"
}
}
@lexer::header
{
extern "C++"
{
#include "header_file.h"
}
}
@lexer::members
{
// #include "members_file.h" // already in parser source code
}
/*
using namespace std;
vector<char*> ArgumentsList;
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
LPWSTR *szArglist;
int nArgs =0;
szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
for (int i = 0; i < nArgs; i++) {
MessageBoxW(NULL, szArglist[i], L"Args", MB_OK);
ArgumentsList.push_back(szArglist[i]);
}
GlobalFree(szArglist);
}
LPWSTR *szArglist;
int nArgs =0;
wchar_t wText [MAX_PATH] = {0};
szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
for (int i = 0; i < nArgs; i++) {
MessageBoxW(NULL, szArglist[i], L"Args", MB_OK);
::MultiByteToWideChar(CP_ACP, NULL, szArglist[i], lstrlenA (szArglist[i]), wText, sizeof(wText));
ArgumentsList.push_back(wText[i]);
}
MessageBoxW(NULL, szArglist[1], L"Args", MB_OK);
GlobalFree(szArglist);
*/
//translation_unit
translation_unit
@init
{
CPPParser__init();
}
: {enterExternalScope();}
(external_declaration)* EOF
{exitExternalScope();
}
;
external_declaration
@init
{
//char *s;
lineNo = LT(1)->line;
boolean K_and_R;
K_and_R = FALSE;
//FunctionSpecifier
fs = fsInvalid; // inline,virtual,explicit
//in_user_file = in_user_file_deferred;
}
:
(
// Template explicit specialisation
('template' LESSTHAN GREATERTHAN)=>
{if(statementTrace>=1)
printf("\%d external_declaration template explicit-specialisation\n",LT(1)->line);
}
'template' LESSTHAN GREATERTHAN external_declaration
|
// All typedefs
('typedef')=>
(
('typedef' 'enum')=>
{if(statementTrace>=1)
printf("\%d external_declaration Typedef enum type\n",LT(1)->line);
}
'typedef' enum_specifier {_td = TRUE;} (init_declarator_list)? SEMICOLON {end_of_stmt();}
|
(declaration_specifiers function_declarator[0] SEMICOLON)=> // DW 11/02/05 This may not be possible
{if(statementTrace>=1)
printf("\%d external_declaration Typedef function type\n",LT(1)->line);
}
declaration
|
(declaration_specifiers (init_declarator_list)? SEMICOLON)=>
{if(statementTrace>=1)
printf("\%d external_declaration Typedef variable type\n",LT(1)->line);
}
declaration
|
('typedef' class_specifier)=>
{if(statementTrace>=1)
printf("\%d external_declaration Typedef class type\n",LT(1)->line);
}
'typedef' class_decl_or_def[fs] {_td = TRUE;} (init_declarator_list)? SEMICOLON {end_of_stmt();}
)
|
// Class template declaration or definition
(template_head (fs = function_specifier)* class_specifier)=>
{if (statementTrace>=1)
printf("\%d external_declaration Templated class decl or def\n",LT(1)->line);
}
template_head (fs = function_specifier)* class_decl_or_def[fs] (init_declarator_list)? SEMICOLON {end_of_stmt();} // declaration
|
// Templated functions and constructors matched here.
{beginTemplateDeclaration();}
template_head
(
// templated forward class decl, init/decl of static member in template
(declaration_specifiers (init_declarator_list)? SEMICOLON {end_of_stmt();})=>
{if (statementTrace>=1)
printf("\%d external_declaration Templated class forward declaration\n",LT(1)->line);
}
declaration_specifiers (init_declarator_list)? SEMICOLON {end_of_stmt();}
|
// Templated function declaration
(declaration_specifiers function_declarator[0] SEMICOLON)=>
{if (statementTrace>=1)
printf("\%d external_declaration Templated function declaration\n",LT(1)->line);
}
declaration
|
// Templated function definition
(declaration_specifiers function_declarator[1] LCURLY)=>
{if (statementTrace>=1)
printf("\%d external_declaration Templated function definition\n",LT(1)->line);
}
function_definition
|
// Templated constructor definition
// JEL 4/3/96 Added predicate that works once the
// restriction is added that ctor cannot be virtual
( ctor_decl_spec
{qualifiedItemIsOneOf(qiCtor,0)}?
)=>
{if (statementTrace>=1)
printf("\%d external_declaration Templated constructor definition\n",LT(1)->line);
}
ctor_definition
)
{endTemplateDeclaration();}
|
// Enum definition (don't want to backtrack over this in other alts)
('enum' (ID)? LCURLY)=>
{if (statementTrace>=1)
printf("\%d external_declaration Enum definition\n",LT(1)->line);
}
enum_specifier (init_declarator_list)? SEMICOLON {end_of_stmt();}
|
// Destructor definition (templated or non-templated)
((template_head)? dtor_head[1] LCURLY)=>
{if (statementTrace>=1)
printf("\%d external_declaration Destructor definition\n",LT(1)->line);
}
(template_head)? dtor_head[1] dtor_body
|
// Constructor definition (non-templated)
// JEL 4/3/96 Added predicate that works, once the
// restriction is added that ctor cannot be virtual
// and ctor_declarator uses a more restrictive id
( (//{dummyVar}? //added by V3-Author //options {warnWhenFollowAmbig = false;}:
ctor_decl_spec)?
{qualifiedItemIsOneOf(qiCtor,0)}?
)=>
{if (statementTrace>=1)
printf("\%d external_declaration Constructor definition\n",LT(1)->line);
}
ctor_definition
|
// User-defined type cast
(('inline')? scope_override conversion_function_decl_or_def)=>
{if (statementTrace>=1)
printf("\%d external_declaration Operator function\n",LT(1)->line);
}
('inline')? s = scope_override conversion_function_decl_or_def
|
// Function declaration
(declaration_specifiers function_declarator[0] SEMICOLON)=>
{if (statementTrace>=1)
printf("\%d external_declaration Function declaration\n",LT(1)->line);
}
declaration_specifiers function_declarator[0] SEMICOLON {end_of_stmt();}
|
// Function definition
(declaration_specifiers function_declarator[1] LCURLY)=>
{if (statementTrace>=1)
printf("\%d external_declaration Function definition\n",LT(1)->line);
}
function_definition
|
// Function definition with int return assumed
(function_declarator[1] LCURLY)=>
{if (statementTrace>=1)
printf("\%d external_declaration Function definition without return type\n",LT(1)->line);
}
function_definition
|
// K & R Function definition
(declaration_specifiers function_declarator[1] declaration)=>
{K_and_R = TRUE;
if (statementTrace>=1)
printf("\%d external_declaration K & R function definition\n",LT(1)->line);
}
function_definition
|
// K & R Function definition with int return assumed
(function_declarator[1] declaration)=>
{K_and_R = TRUE;
if (statementTrace>=1)
printf("\%d external_declaration K & R function definition without return type\n",LT(1)->line);
}
function_definition
|
// Class declaration or definition
(('extern')? (fs = function_specifier)* class_specifier)=>
{if (statementTrace>=1)
printf("\%d external_declaration Class decl or def\n",LT(1)->line);
}
('extern')? (fs = function_specifier)* class_decl_or_def[fs] (init_declarator_list)? SEMICOLON {end_of_stmt();}
// by the V3-Author, concepts, copied from the above class def/decl
//|
// Concept declaration or definition
//('concept' ID LCURLY)=>
//{if (statementTrace>=1)
// fprintf(stderr,"\%d external_declaration Concept decl or def\n\t begining at pos \%d\n",LT(1)->line, LT(1)->charPosition+1);
// }
//concept_decl_or_def
//{
// if (statementTrace>=1)
// fprintf(stderr,"\t ending in line \%d at pos \%d\n",LT(1)->line, LT(1)->charPosition+1);
//}
// SEMICOLON
// {
// end_of_stmt();}
|
// Copied from member_declaration 31/05/07
(declaration_specifiers (init_declarator_list)? SEMICOLON)=>
{if (statementTrace>=1)
printf("\%d external_declaration Declaration\n",LT(1)->line);
}
declaration
|
// Namespace definition
{if (statementTrace>=1)
printf("\%d external_declaration Namespace definition\n",LT(1)->line);
}
'namespace' namespace_definition
|
// Semicolon
{if (statementTrace>=1)
printf("\%d external_declaration Semicolon\n",LT(1)->line);
}
SEMICOLON {end_of_stmt();}
|
// Anything else
{if (statementTrace>=1)
printf("\%d external_declaration Other Declaration\n",LT(1)->line);
}
declaration
|
// The next two entries may be used for debugging
// Use this statement in the source code to turn antlr trace on (See note above)
'antlrTrace_on' {antlrTrace(TRUE);}
|
// Use this statement in the source code to turn antlr trace off (See note above)
'antlrTrace_off' {antlrTrace(FALSE);}
)
;
//member_declaration
member_declaration
//options{backtrack=true;}
@init
{
//char *q;
lineNo = LT(1)->line;
//FunctionSpecifier fs = fsInvalid; // inline,virtual,explicit
}
:
(
// Template explicit specialisation
('template' LESSTHAN GREATERTHAN)=>
{if(statementTrace>=1)
printf("\%d member_declaration Template explicit-specialisation\n",LT(1)->line);
}
'template' LESSTHAN GREATERTHAN member_declaration
|
// All typedefs
//(options{backtrack=true;}:
// (
('typedef')=>
(
('typedef' 'enum')=>
{if(statementTrace>=1)
printf("\%d member_declaration Typedef enum type\n",LT(1)->line);
}
'typedef' enum_specifier {_td = TRUE;} (init_declarator_list)? SEMICOLON {end_of_stmt();}
|
(declaration_specifiers function_declarator[0] SEMICOLON)=> // DW 11/02/05 This may not be possible member declaration
{if(statementTrace>=1)
printf("\%d member_declaration Typedef function type\n",LT(1)->line);
}
declaration
//SEMICOLON
|
(declaration_specifiers (init_declarator_list)? SEMICOLON)=>
{if(statementTrace>=1)
printf("\%d member_declaration Typedef variable type\n",LT(1)->line);
}
declaration
//SEMICOLON
|
('typedef' class_specifier)=>
{if(statementTrace>=1)
printf("\%d member_declaration Typedef class type\n",LT(1)->line);
}
'typedef' class_decl_or_def[fs] {_td = TRUE;} (init_declarator_list)? SEMICOLON {end_of_stmt();}
)
//)
//)
|
// Function declaration
(declaration_specifiers function_declarator[0] SEMICOLON)=>
{if (statementTrace>=1)
printf("\%d member_declaration Function declaration\n",LT(1)->line);
}
declaration_specifiers function_declarator[0] SEMICOLON {end_of_stmt();}
|
// Function definition
(declaration_specifiers function_declarator[1] LCURLY)=>
{if (statementTrace>=1)
printf("\%d member_declaration Function definition\n",LT(1)->line);
}
function_definition
////
|
// Class declaration or definition
(('friend')? (fs = function_specifier)* class_specifier)=>
{if (statementTrace>=1)
printf("\%d member_declaration Class decl or def\n",LT(1)->line);
}
('friend')? (fs = function_specifier)* class_decl_or_def[fs] (init_declarator_list)? SEMICOLON {end_of_stmt();}
|
(declaration_specifiers (init_declarator_list)? SEMICOLON)=>
{if (statementTrace>=1)
printf("\%d member_declaration Declaration\n",LT(1)->line);
}
declaration //HERE//
|
// Member without a type (I guess it can only be a function declaration or definition)
((fs = function_specifier)* function_declarator[0] SEMICOLON)=>
{fprintf(stderr,"\%d warning Function declaration found without return type\n",LT(1)->line);
if (statementTrace>=1)
printf("\%d member_declaration Function declaration\n",LT(1)->line);
}
(fs = function_specifier)* function_declarator[0] SEMICOLON {end_of_stmt();}
|
// Member without a type (I guess it can only be a function definition)
((fs = function_specifier)* function_declarator[1] LCURLY)=>
{fprintf(stderr,"\%d warning Function definition found without return type\n",LT(1)->line);
if (statementTrace>=1)
printf("\%d member_declaration Function definition without return type\n",LT(1)->line);
}
(fs = function_specifier)* function_declarator[1] compound_statement {endFunctionDefinition();}
|
// Templated class declaration or definition
(template_head (fs = function_specifier)* class_specifier)=>
{if (statementTrace>=1)
printf("\%d member_declaration Templated class decl or def\n",LT(1)->line);
}
template_head (fs = function_specifier)* class_decl_or_def[fs] (init_declarator_list)? SEMICOLON {end_of_stmt();} // declaration
|
// Enum definition (don't want to backtrack over this in other alts)
('enum' (ID)? LCURLY)=>
{if (statementTrace>=1)
printf("\%d member_declaration Enum definition\n",LT(1)->line);
}
enum_specifier (init_declarator_list)? SEMICOLON {end_of_stmt();}
|
// Constructor declarator
( ctor_decl_spec
{qualifiedItemIsOneOf(qiCtor,0)}?
ctor_declarator[0] SEMICOLON
)=>
{if (statementTrace>=1)
printf("\%d member_declaration Constructor declarator\n",LT(1)->line);
}
ctor_decl_spec ctor_declarator[0] SEMICOLON {end_of_stmt();}
|
// JEL Predicate to distinguish ctor from function
// This works now that ctor cannot have VIRTUAL
// It unfortunately matches A::A where A is not enclosing
// class -- this will have to be checked semantically
// Constructor definition
( ctor_decl_spec
{qualifiedItemIsOneOf(qiCtor,0)}?
ctor_declarator[1]
(COLON // DEFINITION :ctor_initializer
|LCURLY // DEFINITION (compound Statement) ?
)
)=>
{if (statementTrace>=1)
printf("\%d member_declaration Constructor definition\n",LT(1)->line);
}
ctor_definition
|
// No template_head allowed for dtor member
// Backtrack if not a dtor (no TILDE)
// Destructor declaration
(dtor_head[0] SEMICOLON)=>
{if (statementTrace>=1)
printf("\%d member_declaration Destructor declaration\n",LT(1)->line);
}
dtor_head[0] SEMICOLON {end_of_stmt();}
|//
// No template_head allowed for dtor member
// Backtrack if not a dtor (no TILDE)
// Destructor definition
(dtor_head[1] LCURLY)=>
{if (statementTrace>=1)
printf("\%d member_declaration Destructor definition\n",LT(1)->line);
}
dtor_head[1] dtor_body
|
// User-defined type cast
(('inline')? conversion_function_decl_or_def)=>
{if (statementTrace>=1)
printf("\%d member_declaration Operator function\n",LT(1)->line);
}
('inline')? conversion_function_decl_or_def
|
// Hack to handle decls like "superclass::member",
// to redefine access to private base class public members
// Qualified identifier
(qualified_id SEMICOLON)=>
{if (statementTrace>=1)
printf("\%d member_declaration Qualified ID\n",LT(1)->line);
}
q = qualified_id SEMICOLON {end_of_stmt();}
////
|
// Access specifier
{if (statementTrace>=1)
printf("\%d member_declaration Access specifier\n",LT(1)->line);
}
access_specifier COLON
|
// Semicolon
{if (statementTrace>=1)
printf("\%d member_declaration Semicolon\n",LT(1)->line);
}
SEMICOLON {end_of_stmt();}
|
// The next two entries may be used for debugging
// Use this statement in the source code to turn antlr trace on (See note above)
'antlrTrace_on' {antlrTrace(TRUE);}
|
// Use this statement in the source code to turn antlr trace off (See note above)
'antlrTrace_off' {antlrTrace(FALSE);}
)
;
//namespace_definition
namespace_definition
:
(ns=ID{declaratorID(($ns.text->chars),qiType);})?
LCURLY
{enterNewLocalScope();}
(external_declaration)*
{exitLocalScope();}
RCURLY
;
//namespace_alias_definition
namespace_alias_definition
//{
//char *qid;
//}
:
'namespace'
ns2=ID {declaratorID(($ns2.text->chars),qiType);}
ASSIGNEQUAL qid = qualified_id SEMICOLON {end_of_stmt();}
;
//function_definition
function_definition
@init
{
lineNo = LT(1)->line;
}
:
( // Next line is equivalent to guarded predicate in PCCTS
// (SCOPE | ID)? => <<qualifiedItemIsOneOf(qiType|qiCtor)>>?
{( !(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(qiType|qiCtor,0) )}?
declaration_specifiers function_declarator[1]
( //{dummyVar}? //added by V3-Author //options{warnWhenFollowAmbig = FALSE;}:
(declaration)=>
({lineNo = LT(1)->line;} declaration)* // Possible for K & R definition
{in_parameter_list = FALSE;}
)?
compound_statement
|
function_declarator[1]
( //{dummyVar}? //added by V3-Author //options{warnWhenFollowAmbig = FALSE;}:
(declaration)=>
({lineNo = LT(1)->line;} declaration)* // Possible for K & R definition
{in_parameter_list = FALSE;}
)?
compound_statement
)
{endFunctionDefinition();}
;
//declaration
declaration
:
('extern' StringLiteral)=>
linkage_specification
|
simple_declaration
|
using_statement
;
//linkage_specification
linkage_specification
:
'extern'
StringLiteral
(LCURLY (external_declaration)* RCURLY
|declaration
)
;
//class_head
class_head
: // Used only by predicates
('struct'
|'union'
|'class'
)
(ID
(LESSTHAN template_argument_list GREATERTHAN)?
(base_clause)?
)?
LCURLY
;
//declaration_specifiers
declaration_specifiers
@init
{// Locals
boolean td = FALSE; // For typedef
boolean fd = FALSE; // For friend
sc = scInvalid; // auto,register,static,extern,mutable
tq = tqInvalid; // const,volatile // aka cv_qualifier See type_qualifier
ts = tsInvalid; // char,int,double, etc., class,struct,union
fs = fsInvalid; // inline,virtual,explicit
//}
//:
//{
// Global flags to allow for nested declarations
_td = FALSE; // For typedef
_fd = FALSE; // For friend
_sc = scInvalid; // For StorageClass // auto,register,static,extern,mutable
_tq = tqInvalid; // For TypeQualifier // aka cv_qualifier See type_qualifier
_ts = tsInvalid; // For TypeSpecifier
_fs = fsInvalid; // For FunctionSpecifier // inline,virtual,explicit
}
:
(
(//{dummyVar}? //added by V3-Author //options {warnWhenFollowAmbig = false;}:
'typedef' {td=TRUE;}
| 'friend' {fd=TRUE;}
| sc = storage_class_specifier // auto,register,static,extern,mutable
| tq = type_qualifier // const,volatile // aka cv_qualifier See type_qualifier
| fs = function_specifier // inline,virtual,explicit
| ('_declspec'|'__declspec') LPAREN ID RPAREN
)*
ts = type_specifier
(tq = type_qualifier)* // const,volatile // aka cv_qualifier See type_qualifier
)
{_td=td; declarationSpecifier(td,fd,sc,tq,ts,fs);}
;
//storage_class_specifier
storage_class_specifier returns [StorageClass sc]
@init
{
sc = scInvalid;
}
: 'auto' {sc = scAUTO;}
| 'register' {sc = scREGISTER;}
| 'static' {sc = scSTATIC;}
| 'extern' {sc = scEXTERN;}
| 'mutable' {sc = scMUTABLE;}
;
//function_specifier
function_specifier returns [FunctionSpecifier fs]
@init
{
fs = fsInvalid;
}
: ('inline'|'_inline'|'__inline') {fs = fsINLINE;}
| 'virtual' {fs = fsVIRTUAL;}
| 'explicit' {fs = fsEXPLICIT;}
;
//type_specifier
type_specifier returns [TypeSpecifier ts]
@init
{//char *s;
TypeQualifier tq = tqInvalid;
ts = tsInvalid;
}
: // ts = simple_type_specifier
lbl_ts = simple_type_specifier
//added by V3-Author
{ ts = lbl_ts; }
;
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//simple_type_specifier
simple_type_specifier returns [TypeSpecifier ts]
@init
{
//char *s;
ts = tsInvalid;
}
: //(options{backtrack=true;}:
(
{qualifiedItemIsOneOf(qiType|qiCtor,0)}?
s = qualified_type
|
//lbl_ts changed by V3-Author
('typename'|'enum'| lbl_ts = class_specifier {ts=lbl_ts;})
s = qualified_type
{declaratorID($s.text->chars,qiType);} // This stores typename name in dictionary
|
( 'char' {ts |= tsCHAR;}
| 'wchar_t' {ts |= tsWCHAR_T;}
| 'bool' {ts |= tsBOOL;}
| 'short' {ts |= tsSHORT;}
| 'int' {ts |= tsINT;}
| ('_int8'|'__int8') {ts |= tsINT;}
| ('_int16'|'__int16') {ts |= tsINT;}
| ('_int32'|'__int32') {ts |= tsLONG;}
| ('_int64'|'__int64') {ts |= tsLONG;}
| ('_w64'|'__w64') {ts |= tsLONG;}
| 'long' {ts |= tsLONG;}
| 'signed' {ts |= tsSIGNED;}
| 'unsigned' {ts |= tsUNSIGNED;}
| 'float' {ts |= tsFLOAT;}
| 'double' {ts |= tsDOUBLE;}
| 'void' {ts |= tsVOID;}
)+
)
//)
;
//qualified_type
qualified_type returns [char* qit]
@init
{
//char *so = NULL;
char qitem01[1024];//CPPParser_MaxQualifiedItemSize+1];
qitem01[0] = '\0';
}
:
// JEL 3/29/96 removed this predicate and moved it upwards to
// simple_type_specifier. This was done to allow parsing of ~ID to
// be a unary_expression, which was never reached with this
// predicate on
// {qualifiedItemIsOneOf(qiType|qiCtor,0)}?
so=scope_override
{
if(NULL!=(char*)$so.text->chars)
strcpy(qitem01, (char*)$so.text->chars);
}
id=ID
{
strcat(qitem01, (char*)$id.text->chars);
$qit = qitem01;
}
(//{dummyVar}? //added by V3-Author //options {warnWhenFollowAmbig = false;}:
LESSTHAN template_argument_list GREATERTHAN
)?
;
//class_specifier
class_specifier returns [TypeSpecifier ts]
@init
{
ts = tsInvalid;
}
:
('class' {ts = tsCLASS;}
|'struct' {ts = tsSTRUCT;}
|'union' {ts = tsUNION;}
)
;
//type_qualifier
type_qualifier returns [TypeQualifier tq] // aka cv_qualifier
@init
{
tq = tsInvalid;
}
:
('const' {tq = tqCONST;}
|'volatile' {tq = tqVOLATILE;}
)
;
//class_decl_or_def
class_decl_or_def [FunctionSpecifier fs]
@init
{char *saveClass;
// char *id;
char qid[1024+1];//CPPParser_MaxQualifiedItemSize+1];
TypeSpecifier ts = tsInvalid; // Available for use
}
:
('class' {ts = tsCLASS;}
|'struct' {ts = tsSTRUCT;}
|'union' {ts = tsUNION;}
)
(('_declspec'|'__declspec') LPAREN expression RPAREN)* // Temp for Evgeniy
( id = qualified_id
{strcpy(qid,(char*)$id.text->chars);}
(//{dummyVar}? //added by V3-Author //options{generateAmbigWarnings = false;}:
(SEMICOLON|member_declarator)=>
// Empty
{classForwardDeclaration(qid, ts, fs);} // This stores class name in dictionary
|
(base_clause)?
LCURLY
{saveClass = enclosingClass; enclosingClass = "symbols->strdup(qid)";
beginClassDefinition(qid, ts);} // This stores class name in dictionary
(member_declaration)*
{endClassDefinition();}
RCURLY
{enclosingClass = saveClass;}
)
|
LCURLY
{saveClass = enclosingClass; enclosingClass = "__anonymous";
beginClassDefinition("anonymous", ts);} // This stores "anonymous" name in dictionary
(member_declaration)*
{endClassDefinition();}
RCURLY
{enclosingClass = saveClass;}
)
;
//base_clause
base_clause
:
COLON base_specifier (COMMA base_specifier)*
;
//base_specifier
base_specifier
//{char *qt;}
:
( 'virtual' (access_specifier)? qt = qualified_type
| access_specifier ('virtual')? qt = qualified_type
| qt = qualified_type
)
;
//access_specifier
access_specifier
:
( 'public'
| 'protected'
| 'private'
)
;
//enum_specifier
enum_specifier
//{char *id;}
:
'enum'
(
LCURLY enumerator_list RCURLY
|
id = qualified_id
{beginEnumDefinition((char*)$id.text->chars);} // This stores id name as an enum type in dictionary
(LCURLY enumerator_list RCURLY)?
{endEnumDefinition();}
)
;
//enumerator_list
enumerator_list
:
enumerator (COMMA (enumerator)? )* // Allows comma at end of list
;
//enumerator
enumerator
:
id=ID (ASSIGNEQUAL constant_expression)?
{enumElement((char*)($id.text->chars));} // This stores id name in dictionary
;
// This matches a generic qualified identifier ::T::B::foo
// (including OPERATOR).
// It might be a good idea to put T::~dtor in here
// as well, but id_expression in expr.g puts it in manually.
// Maybe not, 'cause many people use this assuming only A::B.
// How about a 'qualified_complex_id'?
//
//qualified_id
qualified_id returns [char* qid]
@init
{
//char *so = NULL;
//char *op = NULL;
char qitem02[1024+1];//CPPParser_MaxQualifiedItemSize+1];
qitem02[0] = '\0';
}
:
so = scope_override
{
if ( (char*)$so.text->chars ) { strcpy(qitem02, (char*)$so.text->chars); }
}
( id=ID {strcat(qitem02,(char*)($id.text->chars)); /*printf("\%s \n", (char*)$id.text->chars);*/ }
((LESSTHAN template_argument_list GREATERTHAN)=>
LESSTHAN template_argument_list GREATERTHAN)? // {strcat(qitem02,"<...>");}
|
OPERATOR op=optor
{strcat(qitem02,"operator"); strcat(qitem02,(char*)$op.text->chars);}
|
TILDE id_expression // 1/08/07
)
{
$qid = qitem02;
}
;
//////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////
//typeID
typeID
:
{isTypeName((char*)LT(1)->getText(LT(1))->chars)}?
ID
;
//init_declarator_list
init_declarator_list
:
member_declarator (COMMA member_declarator)*
;
//member_declarator
member_declarator
:
((ID)? COLON constant_expression)=>(ID)? COLON constant_expression
|
declarator
(
(ASSIGNEQUAL OCTALINT SEMICOLON)=> ASSIGNEQUAL OCTALINT // The value must be zero (for pure virtual)
|
ASSIGNEQUAL
initializer
|
LPAREN expression_list RPAREN // member function / method declaration
)?
;
//initializer
initializer
:
remainder_expression // assignment_expression
|
LCURLY initializer (COMMA (initializer)? )* RCURLY // Allows comma at end of list
;
//declarator
declarator
:
(ptr_operator)=> ptr_operator // AMPERSAND or STAR etc.
declarator
|
direct_declarator
;
//direct_declarator
direct_declarator
//{
//char *id;
//CPPParser::TypeQualifier tq;
//}
:
(qualified_id LPAREN (RPAREN|declaration_specifiers) )=> // Must be function declaration
id = qualified_id
{if (_td==TRUE) // This statement is a typedef
declaratorID($id.text->chars,qiType);
else
declaratorID($id.text->chars,qiFun);
}
LPAREN {declaratorParameterList(0);}
(parameter_list)?
RPAREN {declaratorEndParameterList(0);}
(tq = type_qualifier)*
(exception_specification)?
|
(qualified_id LPAREN qualified_id)=> // Must be class instantiation
id = qualified_id
{//printf("01\n");
declaratorID($id.text->chars,qiVar);}
LPAREN
expression_list
RPAREN
|
(qualified_id LSQUARE)=> // Must be array declaration
id = qualified_id
{//printf("02\n");
if (_td==TRUE) // This statement is a typedef
declaratorID($id.text->chars,qiType); // This statement is a typedef
else
declaratorID($id.text->chars,qiVar);
is_address = FALSE; is_pointer = FALSE;
}
(//{dummyVar}? //added by V3-Author //options {warnWhenFollowAmbig = false;}:
LSQUARE (constant_expression)? RSQUARE)+
{declaratorArray();}
|
(qualified_id RPAREN LPAREN)=> // Must be function declaration (see function_direct_declarator)
id = qualified_id
{
if (_td==TRUE) // This statement is a typedef
declaratorID($id.text->chars,qiType); // This statement is a typedef
else
declaratorID($id.text->chars,qiFun);
is_address = FALSE; is_pointer = FALSE;
}
|
id = qualified_id
{//printf("03\n");
if (_td==TRUE)
{
declaratorID($id.text->chars,qiType); // This statement is a typedef
}
else
declaratorID($id.text->chars,qiVar);
is_address = FALSE; is_pointer = FALSE;
}
|
LPAREN declarator RPAREN
(//{dummyVar}? //added by V3-Author //options {warnWhenFollowAmbig = false;}:
declarator_suffix)? // DW 1/9/04 declarator_suffix made optional as failed on line 2956 in metrics.i
; // According to the grammar a declarator_suffix is not required here
//declarator_suffix
declarator_suffix // Note: Only used above in direct_declarator
//{CPPParser::TypeQualifier tq;}
:
(
//(options {warnWhenFollowAmbig = false;}:
(LSQUARE (constant_expression)? RSQUARE)+
{declaratorArray();}
|
{(!((LA(1)==LPAREN)&&(LA(2)==ID))||(qualifiedItemIsOneOf(qiType|qiCtor,1)))}?
LPAREN {declaratorParameterList(0);}
(parameter_list)?
RPAREN {declaratorEndParameterList(0);}
(tq = type_qualifier)*
(exception_specification)?
)
;
//{CPPParser::TypeQualifier tq;}
//conversion_function_decl_or_def
conversion_function_decl_or_def
:
OPERATOR declaration_specifiers (STAR | AMPERSAND)? // DW 01/08/03 Use type_specifier here? see syntax
( LESSTHAN template_parameter_list GREATERTHAN /*{wasInTemplate=FALSE;}*/ )?
LPAREN (parameter_list)? RPAREN
(tq = type_qualifier)* // DW 29/07/05 ? changed to *
(exception_specification)?
( compound_statement
| SEMICOLON {end_of_stmt();}
)
;
//function_declarator
function_declarator [int definition]
:
(ptr_operator)=> ptr_operator function_declarator[definition]
|
function_direct_declarator[definition]
;
//function_direct_declarator
function_direct_declarator [int definition]
//{
//char *q;
//CPPParser::TypeQualifier tq;
//}
:
( // fix prompted by (isdigit)() in xlocnum
LPAREN
declarator
RPAREN
|
q = qualified_id
{
declaratorID($q.text->chars,qiFun);
}
)
{
#ifdef MYCODE
if (definition)
myCode_function_direct_declarator(q);
#endif MYCODE
}
LPAREN
{
functionParameterList();
if (K_and_R == TRUE)
in_parameter_list = FALSE;
else
in_parameter_list = TRUE;
}
(parameter_list)?
{
if (K_and_R == TRUE)
in_parameter_list = TRUE;
else
in_parameter_list = FALSE;
}
RPAREN
(//{dummyVar}? //added by V3-Author //options{warnWhenFollowAmbig = false;}:
tq = type_qualifier)*
(ASSIGNEQUAL OCTALINT)? // The value of the octal must be 0
{functionEndParameterList(definition);}
(exception_specification)?
;
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
//ctor_definition
ctor_definition
:
ctor_head
ctor_body
{endConstructorDefinition();}
;
//ctor_head
ctor_head
:
ctor_decl_spec
ctor_declarator[1]
;
//ctor_decl_spec
ctor_decl_spec
:
(('inline'|'_inline'|'__inline')|'explicit')*
;
//ctor_declarator
ctor_declarator[int definition]
:
q = qualified_ctor_id
{declaratorParameterList(definition);}
LPAREN (parameter_list)? RPAREN
{declaratorEndParameterList(definition);}
(exception_specification)?
;
// This matches a generic qualified identifier ::T::B::foo
// that is satisfactory for a ctor (no operator, no trailing <>)
qualified_ctor_id returns [char* q]
@init
{
char qitem03[1024+1];//CPPParser_MaxQualifiedItemSize+1];
qitem03[0] = '\0';
q = NULL;
}
:
so = scope_override
{strcpy(qitem03, (char*)$so.text->chars);}
id=ID // DW 24/05/04 Note. Neither Ctor or Dtor recorded in dictionary
{strcat(qitem03, (char*)($id.text->chars));
$q = qitem03;
//printf("CPP_parser.g qualified_ctor_id q \%s\n",q);
}
;
//ctor_body
ctor_body
:
(ctor_initializer)?
compound_statement
;
//ctor_initializer
ctor_initializer
:
COLON superclass_init (COMMA superclass_init)*
;
//superclass_init
superclass_init
//{char *q;}
:
q = qualified_id LPAREN (expression_list)? RPAREN
;
//dtor_head
dtor_head[int definition]
:
dtor_decl_spec
dtor_declarator[definition]
;
//dtor_decl_spec
dtor_decl_spec
:
(('inline'|'_inline'|'__inline'|'virtual')*)
;
//dtor_declarator
dtor_declarator[int definition]
//{char *s;}
:
s = scope_override
TILDE ID
{declaratorParameterList(definition);}
LPAREN ('void')? RPAREN
{declaratorEndParameterList(definition);}
(exception_specification)?
;
//dtor_body
dtor_body
:
compound_statement
{endDestructorDefinition();}
;
//parameter_list
parameter_list
:
parameter_declaration_list (ELLIPSIS)?
;
//parameter_declaration_list
parameter_declaration_list
:
(parameter_declaration (COMMA parameter_declaration)* )
;
//parameter_declaration (See also template_parameter_declaration)
parameter_declaration
:
{beginParameterDeclaration();}
(
{!((LA(1)==SCOPE) && (LA(2)==STAR||LA(2)==OPERATOR)) &&
(!(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(qiType|qiCtor,0) )}?
declaration_specifiers // DW 24/3/98 Mods for K & R
(
(declarator)=> declarator // if arg name given
|
abstract_declarator // if arg name not given // can be empty
)
|
(declarator)=> declarator // DW 24/3/98 Mods for K & R
|
ELLIPSIS
)
(ASSIGNEQUAL
remainder_expression // DW 18/4/01 assignment_expression
)?
;
//type_id
type_id
:
declaration_specifiers abstract_declarator
;
// This rule looks a bit weird because (...) can happen in two
// places within the declaration such as "void (*)()" (ptr to
// function returning nothing). However, the () of a function
// can only occur after having seen either a (abstract_declarator)
// and not after a [..] or simple '*'. These are the only two
// valid () func-groups:
// int (*)(); // ptr to func
// int (*[])(); // array of ptr to func
//
//abstract_declarator
abstract_declarator
:
ptr_operator abstract_declarator
|
(LPAREN abstract_declarator RPAREN (LSQUARE|LPAREN) )=> LPAREN abstract_declarator RPAREN
(//{dummyVar}? //added by V3-Author //options {warnWhenFollowAmbig = false;}:
abstract_declarator_suffix)
|
(//{dummyVar}? //added by V3-Author //options {warnWhenFollowAmbig = false;}:
abstract_declarator_suffix)?
;
//abstract_declarator_suffix
abstract_declarator_suffix
:
(LSQUARE (constant_expression)? RSQUARE)+
{declaratorArray();}
|
LPAREN
{declaratorParameterList(0);}
(parameter_list)?
RPAREN
{declaratorEndParameterList(0);}
cv_qualifier_seq
(exception_specification)?
;
//exception_specification
exception_specification
//{char *so;}
:
'throw'
LPAREN
( (so = scope_override ID (COMMA so = scope_override ID)* )?
| ELLIPSIS
)
RPAREN
;
//template_head
template_head
:
'template'
LESSTHAN template_parameter_list GREATERTHAN
;
//template_parameter_list
template_parameter_list
:
{ //wasInTemplate=TRUE;
beginTemplateParameterList();}
template_parameter (COMMA template_parameter)*
{endTemplateParameterList();}
;
// Rule requires >2 lookahead tokens. The ambiguity is resolved
// correctly, however. According to the manual "...A template argument
// that can be interpreted either as a parameter-declaration or a
// type-argument (because its identifier is the name of an
// already existing class) is taken as type-argument."
// Therefore, any "class ID" that is seen on the input, should
// match the first alternative here (it should be a type-argument).
//
//template_parameter
template_parameter
:
(//{dummyVar}? //added by V3-Author //options{generateAmbigWarnings = false;}:
type_parameter
|
(parameter_declaration)=>
parameter_declaration
|
template_parameter_declaration
)
;
//type_parameter
type_parameter
:
(
('class'|'typename')
(id=ID
{
templateTypeParameter((char*)$id.text->chars);
}
(ASSIGNEQUAL assigned_type_name)?
)?
|
template_head 'class'
(id2=ID
{
templateTypeParameter((char*)$id2.text->chars);
}
(ASSIGNEQUAL assigned_type_name)?
)?
)
;
// This is to allow an assigned type_name in a template parameter
// list to be defined previously in the same parameter list,
// as type setting is ineffective whilst guessing
//
//assigned_type_name
assigned_type_name
//{char* qt; TypeSpecifier ts;}
:
(//{dummyVar}? //added by V3-Author //options{generateAmbigWarnings = false;}:
qt = qualified_type abstract_declarator
|
ts = simple_type_specifier abstract_declarator
)
;
//template_parameter_declaration (See also parameter_declaration)
template_parameter_declaration
:
{beginParameterDeclaration();}
(
{!((LA(1)==SCOPE) && (LA(2)==STAR||LA(2)==OPERATOR)) &&
(!(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(qiType|qiCtor,0) )}?
declaration_specifiers // DW 24/3/98 Mods for K & R
(
(declarator)=> declarator // if arg name given
|
abstract_declarator // if arg name not given // can be empty
)
|
(declarator)=> declarator // DW 24/3/98 Mods for K & R
|
ELLIPSIS
)
(ASSIGNEQUAL
additive_expression // DW 04/09/07 because of ambiguity of ">"
)?
;
// This rule refers to an instance of a template class or function
//template_id
template_id // aka template_class_name
:
ID LESSTHAN template_argument_list GREATERTHAN
;
//template_argument_list
template_argument_list
:
template_argument (COMMA template_argument)*
;
// Here assignment_expression was changed to shift_expression to rule out
// x< 1<2 > which causes ambiguities. As a result, these can be used only
// by enclosing parentheses x<(1<2)>. This is true for x<1+2> ==> bad,
// x<(1+2)> ==> ok.
//
//template_argument
template_argument
:
// DW 07/04/05 This predicate only used here if next is SCOPE or ID
{( !(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(qiType|qiCtor,0) )}?
type_id
|
shift_expression // failed in iosfwd
;
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
////////////////////////////// STATEMENTS ////////////////////////////
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//statement_list
statement_list
:
(statement)+
;
//statement
statement
@init
{
lineNo = 0;
lineNo = LT(1)->line;
//FunctionSpecifier fs = fsInvalid; // inline,virtual,explicit
}
// all {dummyVar}? are added by V3-Author
:
( ('namespace'|'using')=>
block_declaration
| (('typedef')? class_specifier (qualified_id)? LCURLY)=>
member_declaration
| (declaration_specifiers ((ptr_operator)=>ptr_operator)? qualified_id)=> //HERE//
member_declaration
| (labeled_statement)=>
labeled_statement
| case_statement
| default_statement
| expression SEMICOLON {end_of_stmt();}
| compound_statement
| selection_statement
| iteration_statement
| jump_statement
| SEMICOLON {end_of_stmt();}
| try_block
| throw_statement
// The next two entries may be used for debugging
// Use this statement in the source code to turn antlr trace on (See note above)
| 'antlrTrace_on' {antlrTrace(TRUE);}
// Use this statement in the source code to turn antlr trace off (See note above)
| 'antlrTrace_off' {antlrTrace(FALSE);}
)
;
//block_declaration
block_declaration
: simple_declaration
| namespace_alias_definition
| using_statement
;
//simple_declaration
simple_declaration
:
declaration_specifiers (init_declarator_list)? SEMICOLON {end_of_stmt();}
;
//labeled_statement
labeled_statement
:
ID COLON statement
;
//case_statement
case_statement
: 'case'
constant_expression COLON statement
;
//default_statement
default_statement
:
'default' COLON statement
;
//compound_statement
compound_statement
:
LCURLY
{end_of_stmt();
enterNewLocalScope();
}
(statement_list)?
RCURLY
{exitLocalScope();}
;
// NOTE: cannot remove ELSE ambiguity, but it parses correctly.
// The warning is removed with the options statement
///
//selection_statement
selection_statement
:
'if' LPAREN
{enterNewLocalScope();}
condition RPAREN
st1 = statement
(//{dummyVar}? //added by V3-Author //options {warnWhenFollowAmbig = false;}:
'else' st2 = statement)?
{exitLocalScope();}
|
'switch' LPAREN
{enterNewLocalScope();}
condition RPAREN statement
{exitLocalScope();}
;
//iteration_statement
iteration_statement
:
'while' LPAREN
{enterNewLocalScope();}
condition RPAREN
statement
{exitLocalScope();}
|
'do'
{enterNewLocalScope();}
statement 'while'
LPAREN expression RPAREN
{exitLocalScope();}
SEMICOLON {end_of_stmt();}
|
'for' LPAREN
{enterNewLocalScope();}
( (declaration)=> declaration
| (expression)? SEMICOLON {end_of_stmt();}
)
(condition)? SEMICOLON {end_of_stmt();}
(expression)?
RPAREN statement
{exitLocalScope();}
;
//condition
condition
:
( (declaration_specifiers declarator ASSIGNEQUAL)=>
declaration_specifiers declarator ASSIGNEQUAL remainder_expression
| expression
)
;
//jump_statement
jump_statement
:
( 'goto' ID SEMICOLON {end_of_stmt();}
| 'continue' SEMICOLON {end_of_stmt();}
| 'break' SEMICOLON {end_of_stmt();}
| // DW 16/05/03 May be problem here if return is followed by a cast expression
'return' {in_return = TRUE;}
( //{dummyVar}? //added by V3-Author //options{warnWhenFollowAmbig = false;}:
// THE ,0 was added by V3-Author
(LPAREN {(qualifiedItemIsOneOf(qiType,0) )}? ID RPAREN)=>
LPAREN ID RPAREN (expression)? // This is an unsatisfactory fix for problem in xstring re 'return (allocator);'
// and in xlocale re return (_E)(_Tolower((unsigned char)_C, &_Ctype));
//{printf("\%d CPP_parser.g jump_statement Return fix used\n",lineNo);}
| expression
)? SEMICOLON {in_return = FALSE; end_of_stmt();}
)
;
//try_block
try_block
:
'try' compound_statement (handler)*
;
//handler
handler
:
'catch'
{exceptionBeginHandler();}
{declaratorParameterList(1);}
LPAREN exception_declaration RPAREN
{declaratorEndParameterList(1);}
compound_statement
{exceptionEndHandler();}
;
//exception_declaration
exception_declaration
:
parameter_declaration_list
;
// This is an expression of type void according to the ARM, which
// to me means "statement"; it removes some ambiguity to put it in
// as a statement also.
///
//throw_statement
throw_statement
:
'throw' (assignment_expression) ? SEMICOLON { end_of_stmt();}
;
//using_statement
using_statement
//{char *qid;}
:
'using'
('namespace' qid = qualified_id // Using-directive
|('typename')? qid = qualified_id // Using-declaration
)
SEMICOLON {end_of_stmt();}
;
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
////////////////////////////// EXPRESSIONS ///////////////////////////
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
// Same as expression_list
//expression
expression
@init
{
lineNo = LT(1)->line;
}
:
assignment_expression (COMMA assignment_expression)*
;
// right-to-left for assignment op
//assignment_expression
assignment_expression
:
conditional_expression
( //options{backtrack=true; k=3;}:
(ASSIGNEQUAL|TIMESEQUAL|DIVIDEEQUAL|MINUSEQUAL|PLUSEQUAL
|MODEQUAL|SHIFTLEFTEQUAL|SHIFTRIGHTEQUAL|BITWISEANDEQUAL
|BITWISEXOREQUAL|BITWISEOREQUAL
)
remainder_expression
)?
;
//remainder_expression
remainder_expression
:
(
(conditional_expression (COMMA|SEMICOLON|RPAREN) )=>
{assign_stmt_RHS_found += 1;}
assignment_expression
{
if (assign_stmt_RHS_found > 0)
assign_stmt_RHS_found -= 1;
else
{
fprintf(stderr,"\%d warning Error in assign_stmt_RHS_found = \%d\n",
LT(1)->line,assign_stmt_RHS_found);
fprintf(stderr,"Press return to continue\n");
getchar();
}
}
|
assignment_expression
)
;
//conditional_expression
conditional_expression
:
logical_or_expression
(QUESTIONMARK expression COLON conditional_expression)?
;
//constant_expression
constant_expression
:
conditional_expression
;
//logical_or_expression
logical_or_expression
:
logical_and_expression (OR logical_and_expression)*
;
//logical_and_expression
logical_and_expression
:
inclusive_or_expression (AND inclusive_or_expression)*
;
//inclusive_or_expression
inclusive_or_expression
:
exclusive_or_expression (BITWISEOR exclusive_or_expression)*
;
//exclusive_or_expression
exclusive_or_expression
:
and_expression (BITWISEXOR and_expression)*
;
//and_expression
and_expression
:
equality_expression (AMPERSAND equality_expression)*
;
//equality_expression
equality_expression
:
relational_expression ( (NOTEQUAL|EQUAL) relational_expression)*
;
//relational_expression
relational_expression
:
shift_expression
(options{backtrack=true;}: //added by V3-Author //options {warnWhenFollowAmbig = false;}:
//{!wasInTemplate}?
(
( LESSTHAN
| GREATERTHAN
| LESSTHANOREQUALTO
| GREATERTHANOREQUALTO
)
)shift_expression
)?
;
//shift_expression
shift_expression
:
additive_expression ((SHIFTLEFT | SHIFTRIGHT) additive_expression)*
;
// See comment for multiplicative_expression regarding #pragma
additive_expression
:
multiplicative_expression
(//options{backtrack=true;k=3;}: //added by V3-Author //{dummyVar}? //added by V3-Author //options{warnWhenFollowAmbig = false;}:
(PLUS | MINUS) multiplicative_expression
)*
;
// ANTLR has trouble dealing with the analysis of the confusing unary/binary
// operators such as STAR, AMPERSAND, PLUS, etc...
// With the #pragma (now "(options{warnWhenFollowAmbig = false;}:" etc.)
// we simply tell ANTLR to use the "quick-to-analyze" approximate lookahead
// as full LL(k) lookahead will not resolve the ambiguity anyway. Might
// as well not bother. This has the side-benefit that ANTLR doesn't go
// off to lunch here (take infinite time to read grammar).
multiplicative_expression
:
pm_expression
(//options{backtrack=true;k=3;}: //added by V3-Author //{dummyVar}? //added by V3-Author //options{warnWhenFollowAmbig = false;}:
(STAR|DIVIDE|MOD) pm_expression
)*
;
//pm_expression
pm_expression
:
cast_expression ( (DOTMBR|POINTERTOMBR) cast_expression)*
;
// The string "( ID" can be either the start of a cast or
///the start of a unary_expression. However, the ID must
// be a type name for it to be a cast. Since ANTLR can only hoist
// semantic predicates that are visible without consuming a token,
// the semantic predicate in rule type_name is not hoisted--hence, the
// rule is reported to be ambiguous. I am manually putting in the
// correctly hoisted predicate.
//
// Ack! Actually "( ID" might be the start of "(T(expr))" which makes
// the first parens just an ordinary expression grouping. The solution
// is to look at what follows the type, T. Note, this could be a
// qualified type. Yucko. I believe that "(T(" can only imply
// function-style type cast in an expression (...) grouping.
//
// We DO NOT handle the following situation correctly at the moment:
// Suppose you have
// struct rusage rusage;
// return (rusage.fp);
// return (rusage*)p;
// Now essentially there is an ambiguity here. If rusage is followed by any
// postix operators then it is an identifier else it is a type name. This
// problem does not occur in C because, unless the tag struct is attached,
// rusage is not a type name. However in C++ that restriction is removed.
// No *real* programmer would do this, but it's in the C++ standard just for
// fun..
//
// Another fun one (from an LL standpoint):
//
// (A::B::T *)v; // that's a cast of v to type A::B::T
// (A::B::foo); // that's a simple member access
//
// The qualifiedItemIs(1) function scans ahead to what follows the
// final "::" and returns qiType if the item is a type. The offset of
// '1' makes it ignore the initial LPAREN; normally, the offset is 0.
//
//cast_expression
cast_expression
:
(LPAREN type_id RPAREN unary_expression)=>
LPAREN type_id RPAREN unary_expression
|
// Believe it or not, you can get more than one cast expression in sequence
(LPAREN type_id RPAREN cast_expression)=>
LPAREN type_id RPAREN cast_expression
|
unary_expression // handles outer (...) of "(T(expr))"
;
//unary_expression
unary_expression
:
(
(postfix_expression)=>
postfix_expression
|
PLUSPLUS unary_expression
|
MINUSMINUS unary_expression
|
unary_operator cast_expression
|
('sizeof'
|'__alignof__' //Zhaojz 02/02/05 to fix bug 29 (GNU)
)
( (unary_expression)=>
unary_expression
|
LPAREN type_id RPAREN
)
|
(SCOPE)?
(new_expression
|delete_expression
)
)
;
//postfix_expression
postfix_expression
//@init
//{
//TypeSpecifier ts;
//}
:
//options{backtrack=true;k=3;}: //added by V3-Author //{dummyVar}? //added by V3-Author //options {warnWhenFollowAmbig = false;}:
// Function-style cast must have a leading type
{!(LA(1)==LPAREN)}?
(ts = simple_type_specifier LPAREN RPAREN LPAREN)=> // DW 01/08/03 To cope with problem in xtree (see test10.i)
ts =simple_type_specifier LPAREN RPAREN LPAREN (expression_list)? RPAREN
|
{!(LA(1)==LPAREN)}? =>
(ts = simple_type_specifier LPAREN)=>
ts = simple_type_specifier LPAREN (expression_list)? RPAREN
// Following put in to allow for the above being a constructor as shown in test_constructors_destructors.cpp
(DOT postfix_expression)?
|
primary_expression
(//options{backtrack=true;}: //added by V3-Author //{dummyVar}? //added by V3-Author //options {warnWhenFollowAmbig = false;}:
(LSQUARE expression RSQUARE
| LPAREN (expression_list)? RPAREN // function call/function-call or method call/method-call.
| (DOT|POINTERTO) ('template')? id_expression
| PLUSPLUS
| MINUSMINUS
)*
)
|
('dynamic_cast'|'static_cast'|'reinterpret_cast'|'const_cast')
LESSTHAN ('const')? ts = type_specifier (ptr_operator)? GREATERTHAN
LPAREN expression RPAREN
|
'typeid'
LPAREN ((type_id)=>type_id|expression) RPAREN
( (DOT|POINTERTO) postfix_expression)?
;
//primary_expression
primary_expression
: id_expression
| literal
| 'this'
| LPAREN expression RPAREN
;
//id_expression
id_expression
//{
//char *s;
//}
:
( s = qualified_id
)
;
//literal
literal
://options{backtrack=true;k=2;}:
( OCTALINT
| DECIMALINT
| HEXADECIMALINT
| CharLiteral
| WCharLiteral
| (StringLiteral|WStringLiteral)+
| FLOATONE
| FLOATTWO
| 'true'
| 'false')
;
//unary_operator
unary_operator
:
//options{backtrack=true;}:
AMPERSAND
| STAR
| PLUS
| MINUS
| TILDE
| NOT
;
// JEL The first ()? is used to resolve "new (expr) (type)" because both
// (expr) and (type) look identical until you've seen the whole thing.
//
// new_initializer appears to be conflicting with function arguments as
// function arguments can follow a primary_expression. [This is a full
// LL(k) versus LALL(k) problem. Enhancing context by duplication of
// some rules might handle this.]
///
//new_expression
new_expression
:
(
'new'
( (LPAREN expression_list RPAREN)=>
LPAREN expression_list RPAREN)?
(
(LPAREN type_id RPAREN)=> LPAREN type_id RPAREN
|new_type_id)
(//{dummyVar}? //added by V3-Author //options{warnWhenFollowAmbig = false;}:
(new_initializer)=> new_initializer)?
)
;
//new_initializer
new_initializer
:
LPAREN (expression_list)? RPAREN
;
//new_type_id
new_type_id
:
declaration_specifiers
(//options{backtrack=true;}: //added by V3-Author //options {warnWhenFollowAmbig = false;}:
new_declarator
)?
;
//new_declarator
new_declarator
:
ptr_operator
(//options{backtrack=true;}: //added by V3-Author //options {warnWhenFollowAmbig = false;}:
new_declarator)?
|
direct_new_declarator
;
// The "[expression]" construct conflicts with the "new []" construct
// (and possibly others). We used approximate lookahead for the "new []"
// construct so that it would not try to compute full LL(2) lookahead.
// Here, we use #pragma approx again because anytime we see a [ followed
// by token that can begin an expression, we always want to loop.
// Approximate lookahead handles this correctly. In fact, approximate
// lookahead is the same as full lookahead when all but the last lookahead
// depth are singleton sets; e.g., {"["} followed by FIRST(expression).
///
//direct_new_declarator
direct_new_declarator
:
(//options{backtrack=true;}: //added by V3-Author //options {warnWhenFollowAmbig = false;}:
(LSQUARE expression RSQUARE)
)+
;
//ptr_operator
ptr_operator
//{char *s;}
: //options{backtrack=true;}:
AMPERSAND {is_address = TRUE;} |
('_cdecl'|'__cdecl')
| ('_near'|'__near')
| ('_far'|'__far')
| '__interrupt'
| ('pascal'|'_pascal'|'__pascal')
| ('_stdcall'|'__stdcall')
| (s = scope_override STAR cv_qualifier_seq)=>
s = scope_override STAR {is_pointer = TRUE;} cv_qualifier_seq
;
// Match A::B::* // May be redundant 14/06/06
//ptr_to_member
ptr_to_member // Part of ptr_operator in grammar.txt
//{char *s;}
:
s = scope_override STAR {is_pointer = TRUE;} cv_qualifier_seq
;
// JEL note: does not use (const|volatile)* to avoid lookahead problems
//cv_qualifier_seq
cv_qualifier_seq
//{CPPParser::TypeQualifier tq;}
:
(tq = type_qualifier)*
;
// Match "(::)A::B::C::(template)" or just "::"
//scope_override
scope_override returns [char *so]
@init
{
char sitem[1024+1];//CPPParser_MaxQualifiedItemSize+1];
// The above statement must be non static because its calling is nested
sitem[0] = '\0';
//so = NULL;
}
:
(SCOPE {strcat(sitem,"::");} )?
( //{dummyVar}? //added by V3-Author //options {warnWhenFollowAmbig = false;}:
//{dummyVar2}? //added by V3-Author
(ID LESSTHAN template_argument_list GREATERTHAN SCOPE)=>
id1=ID {strcat(sitem,(char*)($id1.text->chars));}
LESSTHAN template_argument_list GREATERTHAN // {strcat(sitem,"<...>");}
SCOPE{strcat(sitem,"::");}
('template' {strcat(sitem,"template");})?
|
(ID SCOPE)=> // added by V3-Author
//{dummyVar}? //added by V3-Author
id2=ID {strcat(sitem,(char*)($id2.text->chars));}
SCOPE {strcat(sitem,"::");}
('template' {strcat(sitem,"template");})?
)*
{
$so = sitem;
}
;
//delete_expression
delete_expression
:
'delete' (LSQUARE RSQUARE)? cast_expression
;
// Same as expression
//expression_list
expression_list
:
assignment_expression (COMMA assignment_expression)*
;
//optor
optor returns [char* s]
@init
{
char sitem[1024+1];//CPPParser_MaxQualifiedItemSize+1];
//TypeSpecifier ts=tsInvalid;
char *opitem;
sitem[0]='\0';
//s=NULL;
}
: // NOTE: you may need to add backtracking depending on the C++ standard specifications used...
// but for now V3-Author has decided not to add that and go for the default alternative 1 selected
// during antlr code generation...
( 'new' {strcat(sitem," new");}
(//{dummyVar}? //added by V3-Author //options {warnWhenFollowAmbig = false;}:
LSQUARE RSQUARE {strcat(sitem,"[]");} )?
|
'delete' {strcat(sitem," delete");}
(//{dummyVar}? //added by V3-Author //options {warnWhenFollowAmbig = false;}:
LSQUARE RSQUARE {strcat(sitem,"[]");} )?
|
LPAREN RPAREN {strcat(sitem,"()");}
|
LSQUARE RSQUARE {strcat(sitem,"[]");}
|
{strcat(sitem,(char*)(LT(1)->getText(LT(1)))->chars);}
optor_simple_tokclass
|
{strcat(sitem,"type-specifier()");}
ts = type_specifier LPAREN RPAREN
)
{
$s = sitem;
}
;
// optor_simple_tokclass
optor_simple_tokclass
:
//options{backtrack=true;}:
PLUS|MINUS|STAR|DIVIDE|MOD|BITWISEXOR|AMPERSAND|BITWISEOR|TILDE|NOT|
SHIFTLEFT|SHIFTRIGHT|
ASSIGNEQUAL|TIMESEQUAL|DIVIDEEQUAL|MODEQUAL|PLUSEQUAL|MINUSEQUAL|
SHIFTLEFTEQUAL|SHIFTRIGHTEQUAL|BITWISEANDEQUAL|BITWISEXOREQUAL|BITWISEOREQUAL|
EQUAL|NOTEQUAL|LESSTHAN|GREATERTHAN|LESSTHANOREQUALTO|GREATERTHANOREQUALTO|OR|AND|
PLUSPLUS|MINUSMINUS|COMMA|POINTERTO|POINTERTOMBR
;
/////////////////////////////////////////////////////////////
// Operators:
ASSIGNEQUAL : '=' ;
COLON : ':' ;
COMMA : ',' ;
QUESTIONMARK : '?' ;
SEMICOLON : ';' ;
POINTERTO : '->' ;
// DOT & ELLIPSIS are commented out since they are generated as part of
// the Number rule below due to some bizarre lexical ambiguity shme.
DOT : '.' ;
ELLIPSIS : '...' ;
LPAREN : '(' ;
RPAREN : ')' ;
LSQUARE : '[' ;
RSQUARE : ']' ;
LCURLY : '{' ;
RCURLY : '}' ;
EQUAL : '==' ;
NOTEQUAL : '!=' ;
LESSTHANOREQUALTO : '<=' ;
LESSTHAN : '<' ;
GREATERTHANOREQUALTO : '>=' ;
GREATERTHAN : '>' ;
DIVIDE : '/' ;
DIVIDEEQUAL : '/=' ;
PLUS : '+' ;
PLUSEQUAL : '+=' ;
PLUSPLUS : '++' ;
MINUS : '-' ;
MINUSEQUAL : '-=' ;
MINUSMINUS : '--' ;
STAR : '*' ;
TIMESEQUAL : '*=' ;
MOD : '%' ;
MODEQUAL : '%=' ;
SHIFTRIGHT : '>>' ;
SHIFTRIGHTEQUAL : '>>=' ;
SHIFTLEFT : '<<' ;
SHIFTLEFTEQUAL : '<<=' ;
AND : '&&' ;
NOT : '!' ;
OR : '||' ;
AMPERSAND : '&' ;
BITWISEANDEQUAL : '&=' ;
TILDE : '~' ;
//BITWISEAND : ' & ' ;
BITWISEOR : '|' ;
BITWISEOREQUAL : '|=' ;
BITWISEXOR : '^' ;
BITWISEXOREQUAL : '^=' ;
//Zuo: the following tokens are come from cplusplus.g
POINTERTOMBR : '->*' ;
DOTMBR : '.*' ;
SCOPE : '::' ;
Whitespace
:
( // Ignore space
Space
| // handle newlines
( '\r' '\n' // MS
| '\r' // Mac
| '\n' // Unix
) {/*newline();*/}
| // handle continuation lines
( '\\' '\r' '\n' // MS
| '\\' '\r' // Mac
| '\\' '\n' // Unix
) {printf("CPP_parser.g continuation line detected on line \%d\n",$line);
deferredNewline();}
)
{ $channel=HIDDEN; }
;
Comment
:
'/*'
( {LA(2) != '/'}?=> '*'
| EndOfLine {deferredNewline();}
| ~('*'| '\r' | '\n')
)*
'*/' { $channel=HIDDEN; }
;
CPPComment
:
'//' (~('\n' | '\r'))* EndOfLine
{ $channel=HIDDEN; /*newline();*/}
;
PREPROC_DIRECTIVE
//options{paraphrase = 'a line directive';}
@init { paraphrase_push("a line directive"); }
@after { paraphrase_pop(); }
:
'#' LineDirective
{ $channel=HIDDEN; /*newline();*/}
;
fragment
LineDirective
:
('line')? // this would be for if the directive started '#line'
(Space)+
n=Decimal
(Space)+
(sl=StringLiteral)
((Space)+ Decimal)* // To support cpp flags (GNU)
{
process_line_directive((char*)$sl.text->chars, (char*)$n.text->chars); // see main()
}
EndOfLine?
;
fragment
Space
:
(' '|'\t' {tab();}|'\f')
;
Pragma
:
('#' 'pragma' ( (EndOfContinuedLine)=>EndOfContinuedLine
| ~('\r' | '\n')
)*
EndOfLine?
)
{ $channel=HIDDEN; /*newline();*/}
;
Error
:
('#' 'error' ( (EndOfContinuedLine)=>EndOfContinuedLine
| ~('\r' | '\n')
)* EndOfLine
EndOfLine?
)
{ $channel=HIDDEN; /*newline();*/}
;
// Added by V3-Author to eliminate the need for a preprocessor
PreProcDirective
:
('#'
(Space)=> Space*
(
('ifdef')=> 'ifdef'
| ('ifndef')=> 'ifndef'
| ('if')=> 'if'
| ('elif')=> 'elif'
| ('else')=> 'else'
| ('endif')=> 'endif'
| ('undef')=> 'undef'
| ('define')=> 'define'
| ('exec_macro_expression')=> 'exec_macro_expression'
| ('include')=> 'include'
| ('include_next')=> 'include_next'
| ('warning')=> 'warning'
)
( (EndOfContinuedLine)=>EndOfContinuedLine
| ~('\r' | '\n')
)*
EndOfLine?
)
{ $channel=HIDDEN; /*newline();*/}
;
// Literals:
/*
* Note that we do NOT handle tri-graphs nor multi-byte sequences.
*/
/*
* Note that we can't have empty character constants (even though we
* can have empty strings :-).
*/
CharLiteral
:
'\'' ( Escape | UniversalCharacterName | ~('\''|'\\'|'\n'|'\r') ) '\''
;
WCharLiteral
:
'L' CharLiteral
;
/*
* Can't have raw imbedded newlines in string constants. Strict reading of
* the standard gives odd dichotomy between newlines & carriage returns.
* Go figure.
*/
StringLiteral
:
'"'
( Escape
| UniversalCharacterName
| ~('"'|'\\'|'\n'|'\r')
)*
'"'
;
WStringLiteral
:
'L' StringLiteral
;
fragment
EndOfContinuedLine
:
(//{dummyVar}?=> //added by V3-Author //options{generateAmbigWarnings = false;}:
'\\' (Space)* '\r' '\n' // MS
| '\\' (Space)* '\r' // Mac
| '\\' (Space)* '\n' // Unix
) {deferredNewline();}
;
fragment
EndOfLine
:
(//{dummyVar}?=> //added by V3-Author //options{generateAmbigWarnings = false;}:
'\r\n' // MS
| '\r' // Mac
| '\n' // Unix
)
;
/*
* Handle the various escape sequences.
*
* Note carefully that these numeric escape *sequences* are *not* of the
* same form as the C language numeric *constants*.
*
* There is no such thing as a binary numeric escape sequence.
*
* Octal escape sequences are either 1, 2, or 3 octal digits exactly.
*
* There is no such thing as a decimal escape sequence.
*
* Hexadecimal escape sequences are begun with a leading \x and continue
* until a non-hexadecimal character is found.
*
* No real handling of tri-graph sequences, yet.
*/
fragment
Escape
:
'\\'
(// options{warnWhenFollowAmbig=false;}:
'a'
| 'b'
| 'f'
| 'n'
| 'r'
| 't'
| 'v'
| '"'
| '\''
| '\\'
| '?'
| ('0'..'3') (//{dummyVar}?=> //added by V3-Author //options{warnWhenFollowAmbig=false;}:
Digit (//{dummyVar}?=> //added by V3-Author //options{warnWhenFollowAmbig=false;}:
Digit)? )?
| ('4'..'7') (//{dummyVar}?=> //added by V3-Author //options{warnWhenFollowAmbig=false;}:
Digit)?
| 'x' (//{dummyVar}?=> //added by V3-Author //options{warnWhenFollowAmbig=false;}:
HexadecimalDigit)+ //Digit | 'a'..'f' | 'A'..'F')+
)
;
// Numeric Constants:
fragment
Digit
:
'0'..'9'
;
fragment
Decimal
:
('0'..'9')+
;
fragment
LongSuffix
: 'l'
| 'L'
;
fragment
UnsignedSuffix
: 'u'
| 'U'
;
fragment
FloatSuffix
: 'f'
| 'F'
;
fragment
Exponent
:
('e'|'E') ('+'|'-')? (Digit)+
;
fragment
UniversalCharacterName
:
'\\u' HexQuad
| '\\U' HexQuad HexQuad
;
fragment
HexQuad
:
HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit
;
fragment
HexadecimalDigit
:
('0'..'9'|'a'..'f'|'A'..'F')
;
fragment
Vocabulary
:
'\u0003'..'\u0377'
;
Number
:
( (Digit)+ ('.' | 'e' | 'E') )=>
(Digit)+
( '.' (Digit)* (Exponent)? {$type = FLOATONE;} //Zuo 3/12/01
| Exponent {$type = FLOATTWO;} //Zuo 3/12/01
) //{_ttype = DoubleDoubleConst;}
(FloatSuffix //{_ttype = FloatDoubleConst;}
|LongSuffix //{_ttype = LongDoubleConst;}
)?
|
('...')=> '...' {$type = ELLIPSIS;}
|
'.' {$type = DOT;}
( (Digit)+ (Exponent)? {$type = FLOATONE;} //Zuo 3/12/01
//{_ttype = DoubleDoubleConst;}
(FloatSuffix //{_ttype = FloatDoubleConst;}
|LongSuffix //{_ttype = LongDoubleConst;}
)?
)?
|
'0' ('0'..'7')* //{_ttype = IntOctalConst;}
(LongSuffix //{_ttype = LongOctalConst;}
|UnsignedSuffix //{_ttype = UnsignedOctalConst;}
)* {$type = OCTALINT;}
|
'1'..'9' (Digit)* //{_ttype = IntIntConst;}
(LongSuffix //{_ttype = LongIntConst;}
|UnsignedSuffix //{_ttype = UnsignedIntConst;}
)* {$type = DECIMALINT;}
|
'0' ('x' | 'X') (HexadecimalDigit)+ //('a'..'f' | 'A'..'F' | Digit)+
//{_ttype = IntHexConst;}
(LongSuffix //{_ttype = LongHexConst;}
|UnsignedSuffix //{_ttype = UnsignedHexConst;}
)* {$type = HEXADECIMALINT;}
;
ID
//options {testLiterals = true;}
:
(('asm'|'_asm'|'__asm') Whitespace )=>
('asm'|'_asm'|'__asm')
(EndOfLine {deferredNewline();}
|Space
)+
(
LPAREN
( EndOfLine {deferredNewline();}
| ~(')' | '\r' | '\n')
)*
RPAREN { $channel=HIDDEN; }
|
LCURLY
( EndOfLine {deferredNewline();}
| ~('}' | '\r' | '\n')
)*
RCURLY { $channel=HIDDEN; }
|
// Single line asm statement
(~('(' | ')' | '{' | '}' | '\n' | '\r' | ' ' | '\t' | '\f'))
(~('(' | ')' | '{' | '}' | '\n' | '\r'))* (EndOfLine {/*newline();*/})?
{ $channel=HIDDEN; }
)
|
('a'..'z'|'A'..'Z'|'_')
('a'..'z'|'A'..'Z'|'_'|'0'..'9')*
;
fragment
OCTALINT:;
fragment
DECIMALINT:;
fragment
HEXADECIMALINT:;
fragment
FLOATONE:;
fragment
FLOATTWO:;