You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1213 lines
31 KiB
1213 lines
31 KiB
//
|
|
//
|
|
// Pascal Grammar
|
|
//
|
|
// Adapted from,
|
|
// Pascal User Manual And Report (Second Edition-1978)
|
|
// Kathleen Jensen - Niklaus Wirth
|
|
//
|
|
// By
|
|
//
|
|
// Hakki Dogusan dogusanh@tr-net.net.tr
|
|
//
|
|
// Then significantly enhanced by Piet Schoutteten
|
|
// with some guidance by Terence Parr. Piet added tree
|
|
// construction, and some tree walkers.
|
|
//
|
|
//
|
|
// Turbo Pascal, Free Pascal and Delphi pascal extensions
|
|
// by Alexander Dymo <cloudtemple@mksat.net>
|
|
//
|
|
//
|
|
// Adapted from,
|
|
// Free Pascal: Reference Guide 1.9 April 2002
|
|
//
|
|
//
|
|
// KDevelop 3.0 support by Alexander Dymo <cloudtemple@mksat.net>
|
|
//
|
|
|
|
header "pre_include_hpp" {
|
|
#include "problemreporter.h"
|
|
#include "PascalAST.hpp"
|
|
|
|
#include <qlistview.h>
|
|
#include <kdebug.h>
|
|
|
|
#define SET_POSITION(ast,t)\
|
|
{ \
|
|
RefPascalAST(ast)->setLine( t->getLine() );\
|
|
RefPascalAST(ast)->setColumn( t->getColumn() ); \
|
|
}
|
|
}
|
|
|
|
options {
|
|
language="Cpp";
|
|
}
|
|
|
|
class PascalParser extends Parser;
|
|
options {
|
|
k = 2; // two token lookahead
|
|
exportVocab=Pascal; // Call its vocabulary "Pascal"
|
|
codeGenMakeSwitchThreshold = 2; // Some optimizations
|
|
codeGenBitsetTestThreshold = 3;
|
|
defaultErrorHandler = true; // Generate parser error handlers
|
|
buildAST = true;
|
|
ASTLabelType = "RefPascalAST";
|
|
}
|
|
|
|
/* Define imaginary tokens used to organize tree
|
|
*
|
|
* One of the principles here is that any time you have a list of
|
|
* stuff, you usually want to treat it like one thing (a list) a some
|
|
* point in the grammar. You want trees to have a fixed number of children
|
|
* as much as possible. For example, the definition of a procedure should
|
|
* be something like #(PROCEDURE ID #(ARGDECLS ARG1 ARG2...)) not
|
|
* #(PROCEDURE ID ARG1 ARG2 ... ) since this is harder to parse and
|
|
* harder to manipulate. Same is true for statement lists (BLOCK) etc...
|
|
*/
|
|
tokens {
|
|
BLOCK; // list of statements
|
|
IDLIST; // list of identifiers; e.g., #(PROGRAM #(IDLIST ID ID...))
|
|
ELIST; // expression list for proc args etc...
|
|
FUNC_CALL;
|
|
PROC_CALL;
|
|
SCALARTYPE; // IDLIST that is really a scalar type like (Mon,Tue,Wed)
|
|
TYPELIST; // list of types such as for array declarations
|
|
VARIANT_TAG;// for CASEs in a RECORD
|
|
VARIANT_TAG_NO_ID;// for CASEs in a RECORD (no id, just a type)
|
|
VARIANT_CASE;// a case of the variant
|
|
CONSTLIST; // List of constants
|
|
FIELDLIST; // list of fields in a record
|
|
ARGDECLS; // overall group of declarations of args for proc/func.
|
|
VARDECL; // declaration of a variable
|
|
ARGDECL; // declaration of a parameter
|
|
ARGLIST; // list of actual arguments (expressions)
|
|
TYPEDECL; // declaration of a type
|
|
FIELD; // the root a RECORD field
|
|
}
|
|
|
|
// Define some methods and variables to use in the generated parser.
|
|
{
|
|
private:
|
|
unsigned int m_numberOfErrors;
|
|
ProblemReporter* m_problemReporter;
|
|
|
|
public:
|
|
void resetErrors() { m_numberOfErrors = 0; }
|
|
unsigned int numberOfErrors() const { return m_numberOfErrors; }
|
|
void setProblemReporter( ProblemReporter* r ) { m_problemReporter = r; }
|
|
|
|
void reportError( const ANTLR_USE_NAMESPACE(antlr)RecognitionException& ex ){
|
|
m_problemReporter->reportError( ex.getMessage().c_str(),
|
|
ex.getFilename().c_str(),
|
|
ex.getLine(),
|
|
ex.getColumn() );
|
|
++m_numberOfErrors;
|
|
}
|
|
|
|
void reportError( const ANTLR_USE_NAMESPACE(std)string& errorMessage ){
|
|
m_problemReporter->reportError( errorMessage.c_str(),
|
|
getFilename().c_str(),
|
|
LT(1)->getLine(),
|
|
LT(1)->getColumn() );
|
|
++m_numberOfErrors;
|
|
}
|
|
|
|
void reportMessage( const ANTLR_USE_NAMESPACE(std)string& message ){
|
|
m_problemReporter->reportMessage( message.c_str(),
|
|
getFilename().c_str(),
|
|
LT(1)->getLine(),
|
|
LT(1)->getColumn() );
|
|
}
|
|
}
|
|
|
|
compilationUnit
|
|
: program
|
|
| library
|
|
| unit
|
|
;
|
|
|
|
program
|
|
: programHeading
|
|
(usesClause)?
|
|
block
|
|
DOT!
|
|
;
|
|
|
|
library
|
|
: LIBRARY^ identifier SEMI!
|
|
(usesClause)?
|
|
libraryBlock
|
|
exportsClause
|
|
END! DOT!
|
|
;
|
|
|
|
libraryBlock
|
|
: declarationPart (statementPart)?
|
|
;
|
|
|
|
exportsClause
|
|
: EXPORTS^
|
|
exportsList
|
|
;
|
|
|
|
exportsList
|
|
: exportsEntry ( COMMA! exportsEntry )* (SEMI!)?
|
|
;
|
|
|
|
exportsEntry
|
|
: identifier ("index" integerConstant)? ("name" stringConstant)?
|
|
;
|
|
|
|
usesClause
|
|
: USES^ identifierList SEMI!
|
|
;
|
|
|
|
unit
|
|
: UNIT^ identifier SEMI!
|
|
interfacePart
|
|
implementationPart
|
|
( (initializationPart (finalizationPart)?) | realizationPart )?
|
|
END!
|
|
;
|
|
|
|
interfacePart
|
|
: INTERFACE^
|
|
(usesClause)?
|
|
( constantDeclarationPart
|
|
| typeDeclarationPart
|
|
| procedureHeadersPart
|
|
)*
|
|
;
|
|
|
|
implementationPart
|
|
: IMPLEMENTATION^
|
|
(usesClause)?
|
|
declarationPart
|
|
;
|
|
|
|
realizationPart
|
|
: BEGIN^ statement ( SEMI! statement )*
|
|
;
|
|
|
|
programHeading
|
|
: PROGRAM^ identifier (LPAREN! identifierList RPAREN!)? SEMI!
|
|
;
|
|
|
|
initializationPart
|
|
: INITIALIZATION^
|
|
statement ( SEMI! statement )*
|
|
;
|
|
|
|
finalizationPart
|
|
: FINALIZATION^
|
|
statement ( SEMI! statement )*
|
|
;
|
|
|
|
block
|
|
: declarationPart statementPart
|
|
;
|
|
|
|
declarationPart
|
|
: (labelDeclarationPart
|
|
| constantDeclarationPart
|
|
| resourcestringDeclarationPart
|
|
| typeDeclarationPart
|
|
| variableDeclarationPart
|
|
| procedureAndFunctionDeclarationPart
|
|
)*
|
|
;
|
|
|
|
labelDeclarationPart
|
|
: LABEL^ label ( COMMA! label )* SEMI!
|
|
;
|
|
|
|
constantDeclarationPart
|
|
: CONST^ ( constantDeclaration | typedConstantDeclaration )+
|
|
;
|
|
|
|
resourcestringDeclarationPart
|
|
: RESOURCESTRING^ ( stringConstantDeclaration )*
|
|
;
|
|
|
|
stringConstantDeclaration
|
|
: identifier EQUAL! string
|
|
;
|
|
|
|
typeDeclarationPart
|
|
: TYPE^ ( typeDeclaration )+
|
|
;
|
|
|
|
variableDeclarationPart
|
|
: VAR^ variableDeclaration ( SEMI! variableDeclaration )* SEMI!
|
|
;
|
|
|
|
variableDeclaration
|
|
: identifierList c:COLON^ {#c->setType(VARDECL);} type
|
|
;
|
|
|
|
procedureAndFunctionDeclarationPart
|
|
: procedureAndFunctionDeclaration
|
|
;
|
|
|
|
procedureAndFunctionDeclaration
|
|
: procedureDeclaration
|
|
| functionDeclaration
|
|
| constructorDeclaration
|
|
| destructorDeclaration
|
|
;
|
|
|
|
statementPart
|
|
: compoundStatement
|
|
;
|
|
|
|
procedureDeclaration
|
|
: procedureHeader subroutineBlock SEMI!
|
|
;
|
|
|
|
procedureHeadersPart
|
|
: procedureHeader | functionHeader // ) SEMI! ( callModifiers SEMI! )
|
|
;
|
|
|
|
procedureHeader
|
|
: PROCEDURE^ ( identifier | qualifiedMethodIdentifier )
|
|
(formalParameterList)? SEMI! (modifiers SEMI!)*
|
|
;
|
|
|
|
qualifiedMethodIdentifier
|
|
: identifier COLON! COLON! identifier
|
|
;
|
|
|
|
subroutineBlock
|
|
: block
|
|
| externalDirective
|
|
// | asmBlock
|
|
| FORWARD!
|
|
;
|
|
|
|
functionDeclaration
|
|
: functionHeader subroutineBlock SEMI!
|
|
;
|
|
|
|
functionHeader
|
|
: (FUNCTION^ identifier COLON! type SEMI!)=> FUNCTION^ identifier COLON! type SEMI! (modifiers SEMI!)*
|
|
| (FUNCTION^ identifier COLON! COLON! identifier COLON! type SEMI!)=> FUNCTION^ qualifiedMethodIdentifier COLON! type SEMI! (modifiers SEMI!)*
|
|
| (FUNCTION^ identifier COLON! COLON! identifier LPAREN!)=> FUNCTION^ qualifiedMethodIdentifier formalParameterList COLON! type SEMI! (modifiers SEMI!)*
|
|
| FUNCTION^ identifier formalParameterList COLON! type SEMI! (modifiers SEMI!)*
|
|
;
|
|
|
|
functionHeaderEnding
|
|
: (COLON! type SEMI!)=> COLON! type SEMI! (modifiers SEMI!)*
|
|
| formalParameterList COLON! type SEMI! (modifiers SEMI!)*
|
|
;
|
|
|
|
formalParameterList
|
|
: LPAREN! parameterDeclaration ( SEMI! parameterDeclaration )* RPAREN!
|
|
;
|
|
|
|
parameterDeclaration
|
|
: valueParameter
|
|
| variableParameter
|
|
| constantParameter
|
|
;
|
|
|
|
valueParameter
|
|
: (identifierList COLON! ARRAY! OF!)=> identifierList COLON! ARRAY! OF! type
|
|
| identifierList COLON! type
|
|
;
|
|
|
|
variableParameter
|
|
: VAR identifierList ( untypedParameterPart )?
|
|
;
|
|
|
|
untypedParameterPart
|
|
: (COLON! ARRAY! OF! type)=> COLON! ARRAY! OF! type
|
|
| COLON! type
|
|
;
|
|
|
|
constantParameter
|
|
: CONST identifierList ( untypedParameterPart )?
|
|
;
|
|
|
|
externalDirective
|
|
: EXTERNAL^ ( stringConstant ( ("name" stringConstant) | ("index" integerConstant) )? )?
|
|
;
|
|
|
|
/*asmBlock
|
|
: ASSEMBLER^ SEMI! declarationPart asmStatement
|
|
;
|
|
*/
|
|
modifiers
|
|
: PUBLIC! | (ALIAS! stringConstant) | INTERRUPT! | callModifiers | EXPORT!
|
|
;
|
|
|
|
callModifiers
|
|
: REGISTER! | PASCAL! | CDECL! | STDCALL! | POPSTACK! | SAVEREGISTERS! | INLINE! | SAFECALL! | NEAR! | FAR!
|
|
;
|
|
|
|
constantDeclaration
|
|
// : ( identifier EQUAL! expression SEMI! ) ( identifier EQUAL! expression SEMI! )*
|
|
: identifier EQUAL! expression SEMI!
|
|
;
|
|
|
|
typedConstantDeclaration
|
|
// : ( identifier COLON! type EQUAL! typedConstant SEMI! )+
|
|
: identifier COLON! type EQUAL! typedConstant SEMI!
|
|
;
|
|
|
|
//FIXME: is there a better way to handle this instead of simply forcing the rules
|
|
typedConstant
|
|
: (constant)=> constant
|
|
// | addressConstant
|
|
| (LPAREN! identifier COLON!)=> recordConstant
|
|
| (arrayConstant)=> arrayConstant
|
|
| proceduralConstant
|
|
;
|
|
|
|
arrayConstant
|
|
: LPAREN! ( constant | arrayConstant ) ( COMMA! ( constant | arrayConstant ) )* RPAREN!
|
|
;
|
|
|
|
recordConstant
|
|
: LPAREN! ( identifier COLON! constant ) ( SEMI! ( identifier COLON! constant ) )* RPAREN!
|
|
;
|
|
|
|
addressConstant
|
|
: NUM_INT
|
|
;
|
|
|
|
proceduralConstant
|
|
: expression
|
|
;
|
|
|
|
typeDeclaration
|
|
: identifier EQUAL! type SEMI!
|
|
;
|
|
|
|
type
|
|
// : simpleType | subrangeType | enumeratedType | stringType | structuredType | pointerType | proceduralType | typeIdentifier
|
|
: simpleType | subrangeTypeOrTypeIdentifier | enumeratedType | stringType | structuredType | pointerType | proceduralType
|
|
;
|
|
|
|
simpleType
|
|
: ordinalType | realType
|
|
;
|
|
|
|
ordinalType
|
|
: INTEGER! | SHORTINT! | SMALLINT! | LONGINT! | INT64! | BYTE! | WORD! | CARDINAL! | QWORD!
|
|
| BOOLEAN! | BYTEBOOL! | LONGBOOL! | CHAR!
|
|
;
|
|
|
|
subrangeTypeOrTypeIdentifier
|
|
: constant (DOTDOT! constant)?
|
|
;
|
|
|
|
typeIdentifier
|
|
: identifier
|
|
;
|
|
|
|
subrangeType
|
|
: constant DOTDOT! constant
|
|
;
|
|
|
|
enumeratedType
|
|
: (LPAREN! identifier ASSIGN!)=> LPAREN! assignedEnumList RPAREN!
|
|
| LPAREN! identifierList RPAREN!
|
|
;
|
|
|
|
assignedEnumList
|
|
: (identifier ASSIGN! expression) ( COMMA! (identifier ASSIGN! expression) )*
|
|
;
|
|
|
|
realType
|
|
: REAL! | SINGLE! | DOUBLE! | EXTENDED! | COMP!
|
|
;
|
|
|
|
stringType
|
|
: STRING^ ( LBRACK! unsignedInteger RBRACK! )?
|
|
;
|
|
|
|
structuredType
|
|
: (PACKED!)? ( arrayType | recordType | objectType | classType | setType | fileType )
|
|
;
|
|
|
|
arrayType
|
|
: ARRAY^ LBRACK! arrayIndexType ( COMMA! arrayIndexType )* RBRACK! OF! type
|
|
;
|
|
|
|
arrayIndexType
|
|
: ordinalType
|
|
| (expression DOTDOT!)=> arraySubrangeType
|
|
| enumeratedType
|
|
;
|
|
|
|
arraySubrangeType
|
|
: expression DOTDOT! expression
|
|
;
|
|
|
|
recordType
|
|
: RECORD^ (fieldList)* END!
|
|
;
|
|
|
|
fieldList
|
|
: fixedField | variantPart
|
|
;
|
|
|
|
fixedField
|
|
: identifierList COLON! type SEMI!
|
|
;
|
|
|
|
variantPart
|
|
: CASE^ (identifier COLON!)? identifier OF! variant ( SEMI! variant )*
|
|
;
|
|
|
|
variant
|
|
: (constant COMMA!)+ COLON! LPAREN! (fieldList)* RPAREN!
|
|
;
|
|
|
|
setType
|
|
: SET^ OF! ordinalType
|
|
;
|
|
|
|
fileType
|
|
: FILE^ OF! type
|
|
;
|
|
|
|
pointerType
|
|
: POINTER^ typeIdentifier
|
|
;
|
|
|
|
proceduralType
|
|
: (proceduralTypePart1 SEMI!)=> proceduralTypePart1 SEMI! callModifiers
|
|
| proceduralTypePart1
|
|
;
|
|
|
|
proceduralTypePart1
|
|
: ( functionHeader | procedureHeader ) (OF! OBJECT!)?
|
|
;
|
|
|
|
objectType
|
|
: OBJECT^ (heritage)? (componentList | objectVisibilitySpecifier ) END!
|
|
;
|
|
|
|
heritage
|
|
: LPAREN! identifier RPAREN!
|
|
;
|
|
|
|
componentList
|
|
: ( (fieldDefinition)+ )? ( (methodDefinition)+ )?
|
|
;
|
|
|
|
fieldDefinition
|
|
: identifierList COLON! type SEMI!
|
|
;
|
|
|
|
methodDefinition
|
|
: ( functionHeader | procedureHeader | constructorHeader | destructorHeader ) SEMI! methodDirectives
|
|
;
|
|
|
|
methodDirectives
|
|
: ( VIRTUAL! SEMI! (ABSTRACT! SEMI!)? )? (callModifiers SEMI!)?
|
|
;
|
|
|
|
objectVisibilitySpecifier
|
|
: PRIVATE! | PROTECTED! | PUBLIC!
|
|
;
|
|
|
|
constructorDeclaration
|
|
: constructorHeader SEMI! subroutineBlock
|
|
;
|
|
|
|
destructorDeclaration
|
|
: destructorHeader SEMI! subroutineBlock
|
|
;
|
|
|
|
constructorHeader
|
|
: CONSTRUCTOR^ ( identifier | qualifiedMethodIdentifier ) formalParameterList
|
|
;
|
|
|
|
destructorHeader
|
|
: DESTRUCTOR^ ( identifier | qualifiedMethodIdentifier ) formalParameterList
|
|
;
|
|
|
|
classType
|
|
: CLASS^ (heritage)? (classComponentList | classVisibilitySpecifier ) END!
|
|
;
|
|
|
|
classComponentList
|
|
: ( (fieldDefinition)+ )? ( ( (classMethodDefinition | propertyDefinition) )+ )?
|
|
;
|
|
|
|
classMethodDefinition
|
|
: ( ( (CLASS!)? (functionHeader | procedureHeader) ) | constructorHeader | destructorHeader ) SEMI! classMethodDirectives
|
|
;
|
|
|
|
classMethodDirectives
|
|
: ( directiveVariants SEMI! )? (callModifiers SEMI!)?
|
|
;
|
|
|
|
directiveVariants
|
|
: ( VIRTUAL! (ABSTRACT! SEMI!)? )
|
|
| OVERRIDE!
|
|
| (MESSAGE! (integerConstant | stringConstant))
|
|
;
|
|
|
|
classVisibilitySpecifier
|
|
: PRIVATE! | PROTECTED! | PUBLIC! | PUBLISHED!
|
|
;
|
|
|
|
propertyDefinition
|
|
: PROPERTY^ identifier (propertyInterface)? propertySpecifiers
|
|
;
|
|
|
|
propertyInterface
|
|
: (propertyParameterList)? COLON! typeIdentifier ("index" integerConstant)?
|
|
;
|
|
|
|
propertyParameterList
|
|
: LBRACK! parameterDeclaration (SEMI! parameterDeclaration)* RBRACK!
|
|
;
|
|
|
|
propertySpecifiers
|
|
: (readSpecifier)? (writeSpecifier)? (defaultSpecifier)?
|
|
;
|
|
|
|
readSpecifier
|
|
: "read" fieldOrMethod
|
|
;
|
|
|
|
writeSpecifier
|
|
: "write" fieldOrMethod
|
|
;
|
|
|
|
defaultSpecifier
|
|
: ( DEFAULT (constant)? )
|
|
| "nodefault"
|
|
;
|
|
|
|
fieldOrMethod
|
|
: identifier
|
|
;
|
|
|
|
expression
|
|
: simpleExpression ( expressionSign simpleExpression )?
|
|
;
|
|
|
|
expressionSign
|
|
// : STAR! | LE! | GE! | LTH! | GT! | NOT_EQUAL! | IN! | IS!
|
|
: LE! | GE! | LTH! | GT! | NOT_EQUAL! | IN! | IS! | EQUAL!
|
|
;
|
|
|
|
simpleExpression
|
|
: term ( ( PLUS! | MINUS! | OR! | XOR! ) term )*
|
|
;
|
|
|
|
term
|
|
: factor ( (STAR! | SLASH! | DIV! | MOD! | AND! | SHL! | SHR!) factor )*
|
|
;
|
|
|
|
//TODO: distinguish between identifiers, typecasts and function calls -> semantic predicate
|
|
factor
|
|
: ( LPAREN! expression RPAREN! )
|
|
// | (qualifiedMethodIdentifier2 LBRACK!)=> qualifiedMethodIdentifier2 LBRACK! arrayIndexType ( COMMA! arrayIndexType )* RBRACK!
|
|
| identifierOrValueTypecastOrFunctionCall
|
|
// | identifier
|
|
// | functionCall
|
|
| unsignedConstant
|
|
| ( NOT! factor )
|
|
| ( (PLUS! | MINUS!) factor )
|
|
| setConstructor
|
|
// | valueTypecast
|
|
| addressFactor
|
|
| TRUE
|
|
| FALSE
|
|
| identifier LBRACK! expression ( COMMA! expression )* RBRACK!
|
|
;
|
|
|
|
//FIXME: is this correct?
|
|
identifierOrValueTypecastOrFunctionCall
|
|
: (identifier LPAREN! expression COMMA!)=> identifier LPAREN! expressions RPAREN!
|
|
| (identifier LPAREN! expression RPAREN!)=> identifier LPAREN! expression RPAREN!
|
|
// | (qualifiedMethodIdentifier2 LPAREN! expression COMMA!)=> qualifiedMethodIdentifier2 LPAREN! expressions RPAREN!
|
|
// | (identifier DOT)=> qualifiedMethodIdentifier2
|
|
| identifier
|
|
;
|
|
|
|
/*qualifiedMethodIdentifier2
|
|
: identifier DOT identifier
|
|
;
|
|
*/
|
|
//( functionIdentifier | methodDesignator | qualifiedMethodDesignator | variableReference )
|
|
functionCall
|
|
: identifier (actualParameterList)?
|
|
;
|
|
|
|
actualParameterList
|
|
: LPAREN! ( expressions )? RPAREN!
|
|
;
|
|
|
|
expressions
|
|
: expression ( COMMA! expression )*
|
|
;
|
|
|
|
setConstructor
|
|
: LBRACK! ( setGroup ( COMMA! setGroup )* )? RBRACK!
|
|
;
|
|
|
|
setGroup
|
|
: expression ( DOT! DOT! expression )?
|
|
;
|
|
|
|
valueTypecast
|
|
: typeIdentifier LPAREN! expression RPAREN!
|
|
;
|
|
|
|
//( variableReference | procedureIdentifier | functionIdentifier | qualifiedMethodIdentifier )
|
|
addressFactor
|
|
: AT! identifier
|
|
;
|
|
|
|
statement
|
|
// : (label COLON!)? (simpleStatement | structuredStatement | asmStatement)
|
|
: (label COLON!)? (simpleStatement | structuredStatement)
|
|
;
|
|
|
|
simpleStatement
|
|
: assignmentStatement | procedureStatement | gotoStatement | raiseStatement
|
|
;
|
|
|
|
assignmentStatement
|
|
: identifierOrArrayIdentifier assignmentOperator expression
|
|
;
|
|
|
|
identifierOrArrayIdentifier
|
|
: identifier
|
|
// | (qualifiedMethodIdentifier LBRACK!)=> qualifiedMethodIdentifier LBRACK! arrayIndexType ( COMMA! arrayIndexType )* RBRACK!
|
|
// | qualifiedMethodIdentifier
|
|
| identifier LBRACK! expression ( COMMA! expression )* RBRACK!
|
|
;
|
|
|
|
assignmentOperator
|
|
: ASSIGN! | PLUSEQ | MINUSEQ | STAREQ | SLASHQE
|
|
;
|
|
|
|
procedureStatement
|
|
: identifier (actualParameterList)?
|
|
;
|
|
|
|
gotoStatement
|
|
: GOTO! label
|
|
;
|
|
|
|
structuredStatement
|
|
: compoundStatement | repetitiveStatement | conditionalStatement | exceptionStatement | withStatement
|
|
;
|
|
|
|
conditionalStatement
|
|
: ifStatement | caseStatement
|
|
;
|
|
|
|
repetitiveStatement
|
|
: forStatement | repeatStatement | whileStatement
|
|
;
|
|
|
|
compoundStatement
|
|
: BEGIN! END!
|
|
| BEGIN! (SEMI!)+ END!
|
|
| BEGIN! statement (SEMI! (statement)?)* END!
|
|
;
|
|
|
|
ifStatement
|
|
: IF^ expression THEN! statement
|
|
(
|
|
// CONFLICT: the old "dangling-else" problem...
|
|
// ANTLR generates proper code matching
|
|
// as soon as possible. Hush warning.
|
|
options {
|
|
generateAmbigWarnings=false;
|
|
}
|
|
: ELSE! statement
|
|
)?
|
|
;
|
|
|
|
caseStatement
|
|
: CASE^ expression OF!
|
|
caseListElement ( SEMI! caseListElement )*
|
|
( SEMI! ELSE! statement ( SEMI! statement )* )?
|
|
END!
|
|
;
|
|
|
|
caseListElement
|
|
: constList COLON^ statement
|
|
;
|
|
|
|
constList
|
|
: constant ( COMMA! constant )*
|
|
{#constList = #([CONSTLIST],#constList);}
|
|
;
|
|
|
|
whileStatement
|
|
: WHILE^ expression DO! statement
|
|
;
|
|
|
|
repeatStatement
|
|
: REPEAT^ statement ( SEMI! (statement)? )* UNTIL! expression
|
|
;
|
|
|
|
forStatement
|
|
: FOR^ identifier ASSIGN! forList DO! statement
|
|
;
|
|
|
|
forList
|
|
: initialValue (TO^ | DOWNTO^) finalValue
|
|
;
|
|
|
|
initialValue
|
|
: expression
|
|
;
|
|
|
|
finalValue
|
|
: expression
|
|
;
|
|
|
|
withStatement
|
|
: WITH^ recordVariableList DO! statement
|
|
;
|
|
|
|
recordVariableList
|
|
: variable ( COMMA! variable )*
|
|
;
|
|
|
|
/** A variable is an id with a suffix and can look like:
|
|
* id
|
|
* id[expr,...]
|
|
* id.id
|
|
* id.id[expr,...]
|
|
* id^
|
|
* id^.id
|
|
* id^.id[expr,...]
|
|
* ...
|
|
*
|
|
* LL has a really hard time with this construct as it's naturally
|
|
* left-recursive. We have to turn into a simple loop rather than
|
|
* recursive loop, hence, the suffixes. I keep in the same rule
|
|
* for easy tree construction.
|
|
*/
|
|
variable
|
|
: ( AT^ identifier // AT is root of identifier; then other op becomes root
|
|
| identifier
|
|
)
|
|
( LBRACK^ expression ( COMMA! expression)* RBRACK!
|
|
| LBRACK2^ expression ( COMMA! expression)* RBRACK2!
|
|
| DOT^ identifier
|
|
| POINTER^
|
|
)*
|
|
;
|
|
|
|
/*asmStatement
|
|
: ASM^ assemblerCode END! (registerList)?
|
|
;
|
|
|
|
registerList
|
|
: LBRACK! stringConstant ( COMMA! stringConstant )*
|
|
;
|
|
|
|
assemblerCode
|
|
: (.)*
|
|
;
|
|
*/
|
|
operatorDefinition
|
|
: OPERATOR^ ( assignmentOperatorDefinition | arithmeticOperatorDefinition | comparisonOperatorDefinition )
|
|
identifier COLON! type SEMI! subroutineBlock
|
|
;
|
|
|
|
assignmentOperatorDefinition
|
|
: ASSIGN! LPAREN! valueParameter RPAREN!
|
|
;
|
|
|
|
arithmeticOperatorDefinition
|
|
: ( PLUS! | MINUS! | STAR! | SLASH! | (STAR! STAR!) ) LPAREN! formalParameterList RPAREN!
|
|
;
|
|
|
|
comparisonOperatorDefinition
|
|
: ( EQUAL! | LE! | GE! | GT! | LTH! ) LPAREN! formalParameterList RPAREN!
|
|
;
|
|
|
|
raiseStatement
|
|
: RAISE^ ( functionCall (AT! addressConstant)? )?
|
|
;
|
|
|
|
exceptionStatement
|
|
: tryStatement
|
|
;
|
|
|
|
tryStatement
|
|
: TRY^ (statements)? exceptOrFinallyPart END!
|
|
;
|
|
|
|
exceptOrFinallyPart
|
|
: EXCEPT! (exceptionHandlers)?
|
|
| FINALLY! (statements)?
|
|
;
|
|
|
|
statements
|
|
: statement ( SEMI! statement )*
|
|
;
|
|
|
|
exceptionHandlers
|
|
: statements | exceptionHandler ( SEMI! exceptionHandler )* ( ELSE! statements )?
|
|
;
|
|
|
|
exceptionHandler
|
|
: ON! (identifier COLON!)? identifier DO! statement
|
|
;
|
|
|
|
identifierList
|
|
: identifier ( COMMA! identifier )*
|
|
{#identifierList = #(#[IDLIST],#identifierList);}
|
|
;
|
|
|
|
label
|
|
: unsignedInteger
|
|
;
|
|
|
|
unsignedInteger
|
|
: NUM_INT
|
|
;
|
|
|
|
integerConstant
|
|
: unsignedInteger
|
|
|! s:sign n:unsignedInteger { #integerConstant=#(s,n); }
|
|
;
|
|
|
|
stringConstant
|
|
: string | constantChr
|
|
;
|
|
|
|
sign
|
|
: PLUS | MINUS
|
|
;
|
|
|
|
string
|
|
: STRING_LITERAL
|
|
;
|
|
|
|
constantChr
|
|
: CHR^ LPAREN! unsignedInteger RPAREN!
|
|
;
|
|
|
|
constant
|
|
: unsignedNumber
|
|
|! s:sign n:unsignedNumber { #constant=#(s,n); }
|
|
| identifier
|
|
|! s2:sign id:identifier { #constant=#(s2,id); }
|
|
| string
|
|
| constantChr
|
|
;
|
|
|
|
unsignedConstant
|
|
: unsignedNumber | constantChr | string | NIL!
|
|
;
|
|
|
|
unsignedNumber
|
|
: unsignedInteger
|
|
| unsignedReal
|
|
;
|
|
|
|
unsignedReal
|
|
: NUM_REAL
|
|
;
|
|
|
|
identifier
|
|
: IDENT
|
|
;
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// The Pascal scanner
|
|
//----------------------------------------------------------------------------
|
|
class PascalLexer extends Lexer;
|
|
|
|
options {
|
|
charVocabulary = '\0'..'\377';
|
|
exportVocab = Pascal; // call the vocabulary "Pascal"
|
|
testLiterals = false; // don't automatically test for literals
|
|
k = 4; // four characters of lookahead
|
|
caseSensitive = false;
|
|
caseSensitiveLiterals = false;
|
|
defaultErrorHandler=false;
|
|
}
|
|
|
|
tokens {
|
|
ABSOLUTE = "absolute" ;
|
|
ABSTRACT = "abstract" ;
|
|
ALIAS = "alias" ;
|
|
AND = "and" ;
|
|
ARRAY = "array" ;
|
|
AS = "as" ;
|
|
ASM = "asm" ;
|
|
ASSEMBLER = "assembler" ;
|
|
BEGIN = "begin" ;
|
|
BREAK = "break" ;
|
|
BOOLEAN = "boolean" ;
|
|
BYTE = "byte" ;
|
|
CARDINAL = "cardinal" ;
|
|
CASE = "case" ;
|
|
CDECL = "cdecl" ;
|
|
CHAR = "char" ;
|
|
CHR = "chr" ;
|
|
CLASS = "class" ;
|
|
COMP = "comp" ;
|
|
CONST = "const" ;
|
|
CONSTRUCTOR = "constructor" ;
|
|
CONTINUE = "continue" ;
|
|
DEFAULT = "default" ;
|
|
DESTRUCTOR = "destructor" ;
|
|
DISPOSE = "dispose" ;
|
|
DIV = "div" ;
|
|
DO = "do" ;
|
|
DOUBLE = "double" ;
|
|
DOWNTO = "downto" ;
|
|
ELSE = "else" ;
|
|
END = "end" ;
|
|
EXCEPT = "except" ;
|
|
EXPORT = "export" ;
|
|
EXPORTS = "exports" ;
|
|
EXTENDED = "extended" ;
|
|
EXTERNAL = "external" ;
|
|
EXIT = "exit" ;
|
|
FALSE = "false" ;
|
|
FILE = "file" ;
|
|
FINALLY = "finally" ;
|
|
FAR = "far" ;
|
|
FOR = "for" ;
|
|
FORWARD = "forward" ;
|
|
FUNCTION = "function" ;
|
|
GOTO = "goto" ;
|
|
IF = "if" ;
|
|
IN = "in" ;
|
|
// INDEX = "index" ;
|
|
IS = "is" ;
|
|
INHERITED = "inherited" ;
|
|
INLINE = "inline" ;
|
|
INT64 = "int64" ;
|
|
INTEGER = "integer" ;
|
|
LABEL = "label" ;
|
|
LIBRARY = "library" ;
|
|
LONGINT = "longint" ;
|
|
MOD = "mod" ;
|
|
// NAME = "name" ;
|
|
NEAR = "near" ;
|
|
NEW = "new" ;
|
|
NIL = "nil" ;
|
|
NOT = "not" ;
|
|
OBJECT = "object" ;
|
|
OF = "of" ;
|
|
ON = "on" ;
|
|
OPERATOR = "operator" ;
|
|
OR = "or" ;
|
|
OVERRIDE = "override" ;
|
|
PACKED = "packed" ;
|
|
PASCAL = "pascal" ;
|
|
POPSTACK = "popstack" ;
|
|
PRIVATE = "private" ;
|
|
PROCEDURE = "procedure" ;
|
|
PROTECTED = "protected" ;
|
|
PROGRAM = "program" ;
|
|
PROPERTY = "property" ;
|
|
PUBLIC = "public" ;
|
|
PUBLISHED = "published" ;
|
|
QWORD = "qword" ;
|
|
RAISE = "raise" ;
|
|
REAL = "real" ;
|
|
RECORD = "record" ;
|
|
REGISTER = "register" ;
|
|
REPEAT = "repeat" ;
|
|
SAFECALL = "safecall" ;
|
|
SAVEREGISTERS = "saveregisters" ;
|
|
SELF = "self" ;
|
|
SET = "set" ;
|
|
SHORTINT = "shortint" ;
|
|
SHR = "shr" ;
|
|
SHL = "shl" ;
|
|
SINGLE = "single" ;
|
|
SMALLINT = "smallint" ;
|
|
STDCALL = "stdcall" ;
|
|
THEN = "then" ;
|
|
TO = "to" ;
|
|
TRUE = "true" ;
|
|
TRY = "try" ;
|
|
TYPE = "type" ;
|
|
UNTIL = "until" ;
|
|
VAR = "var" ;
|
|
VIRTUAL = "virtual" ;
|
|
WHILE = "while" ;
|
|
WITH = "with" ;
|
|
WORD = "word" ;
|
|
XOR = "xor" ;
|
|
METHOD ;
|
|
ADDSUBOR ;
|
|
ASSIGNEQUAL ;
|
|
SIGN ;
|
|
FUNC ;
|
|
NODE_NOT_EMIT ;
|
|
MYASTVAR ;
|
|
LF ;
|
|
UNIT = "unit" ;
|
|
INTERFACE = "interface" ;
|
|
USES = "uses" ;
|
|
STRING = "string" ;
|
|
IMPLEMENTATION = "implementation" ;
|
|
FINALIZATION = "finalization" ;
|
|
INITIALIZATION = "initialization" ;
|
|
RESOURCESTRING = "resourcestring" ;
|
|
//pspsps ???
|
|
}
|
|
|
|
{
|
|
private:
|
|
ProblemReporter* m_problemReporter;
|
|
unsigned int m_numberOfErrors;
|
|
|
|
public:
|
|
void resetErrors() { m_numberOfErrors = 0; }
|
|
unsigned int numberOfErrors() const { return m_numberOfErrors; }
|
|
void setProblemReporter( ProblemReporter* r ) { m_problemReporter = r; }
|
|
|
|
virtual void reportError( const ANTLR_USE_NAMESPACE(antlr)RecognitionException& ex ){
|
|
m_problemReporter->reportError( ex.getMessage().c_str(),
|
|
ex.getFilename().c_str(),
|
|
ex.getLine(),
|
|
ex.getColumn() );
|
|
++m_numberOfErrors;
|
|
}
|
|
|
|
virtual void reportError( const ANTLR_USE_NAMESPACE(std)string& errorMessage ){
|
|
m_problemReporter->reportError( errorMessage.c_str(),
|
|
getFilename().c_str(),
|
|
getLine(), getColumn() );
|
|
++m_numberOfErrors;
|
|
}
|
|
|
|
virtual void reportWarning( const ANTLR_USE_NAMESPACE(std)string& warnMessage ){
|
|
m_problemReporter->reportWarning( warnMessage.c_str(),
|
|
getFilename().c_str(),
|
|
getLine(), getColumn() );
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// OPERATORS
|
|
//----------------------------------------------------------------------------
|
|
PLUS : '+' ;
|
|
MINUS : '-' ;
|
|
STAR : '*' ;
|
|
SLASH : '/' ;
|
|
ASSIGN : ":=" ;
|
|
COMMA : ',' ;
|
|
SEMI : ';' ;
|
|
COLON : ':' ;
|
|
EQUAL : '=' ;
|
|
NOT_EQUAL : "<>" ;
|
|
LTH : '<' ;
|
|
LE : "<=" ;
|
|
GE : ">=" ;
|
|
GT : '>' ;
|
|
LPAREN : '(' ;
|
|
RPAREN : ')' ;
|
|
LBRACK : '[' ; // line_tab[line]
|
|
LBRACK2 : "(." ; // line_tab(.line.)
|
|
RBRACK : ']' ;
|
|
RBRACK2 : ".)" ;
|
|
POINTER : '^' ;
|
|
AT : '@' ;
|
|
DOT : '.' ('.' {$setType(DOTDOT);})? ;
|
|
LCURLY : "{" ;
|
|
RCURLY : "}" ;
|
|
PLUSEQ : "+=" ;
|
|
MINUSEQ : "-=" ;
|
|
STAREQ : "*=" ;
|
|
SLASHQE : "/=" ;
|
|
|
|
|
|
// Whitespace -- ignored
|
|
WS : ( ' '
|
|
| '\t'
|
|
| '\f'
|
|
// handle newlines
|
|
| ( "\r\n" // Evil DOS
|
|
| '\r' // Macintosh
|
|
| '\n' // Unix (the right way)
|
|
)
|
|
{ newline(); }
|
|
)
|
|
{ _ttype = ANTLR_USE_NAMESPACE(antlr)Token::SKIP; }
|
|
;
|
|
|
|
|
|
COMMENT_1
|
|
: "(*"
|
|
( options { generateAmbigWarnings=false; }
|
|
: { LA(2) != ')' }? '*'
|
|
| '\r' '\n' {newline();}
|
|
| '\r' {newline();}
|
|
| '\n' {newline();}
|
|
| ~('*' | '\n' | '\r')
|
|
)*
|
|
"*)"
|
|
{$setType(ANTLR_USE_NAMESPACE(antlr)Token::SKIP);}
|
|
;
|
|
|
|
COMMENT_2
|
|
: '{'
|
|
( options {generateAmbigWarnings=false;}
|
|
: '\r' '\n' {newline();}
|
|
| '\r' {newline();}
|
|
| '\n' {newline();}
|
|
| ~('}' | '\n' | '\r')
|
|
)*
|
|
'}'
|
|
{$setType(ANTLR_USE_NAMESPACE(antlr)Token::SKIP);}
|
|
;
|
|
|
|
COMMENT_3
|
|
: "//" (~'\n')* '\n'
|
|
{$setType(ANTLR_USE_NAMESPACE(antlr)Token::SKIP);}
|
|
;
|
|
|
|
// an identifier. Note that testLiterals is set to true! This means
|
|
// that after we match the rule, we look in the literals table to see
|
|
// if it's a literal or really an identifer
|
|
IDENT
|
|
options {testLiterals=true;}
|
|
: ('a'..'z') ('a'..'z'|'0'..'9'|'_')* //pspsps
|
|
;
|
|
|
|
// string literals
|
|
STRING_LITERAL
|
|
: '\'' ("\'\'" | ~('\''))* '\'' //pspsps * in stead of + because of e.g. ''
|
|
;
|
|
|
|
/** a numeric literal. Form is (from Wirth)
|
|
* digits
|
|
* digits . digits
|
|
* digits . digits exponent
|
|
* digits exponent
|
|
*/
|
|
NUM_INT
|
|
: ('0'..'9')+ // everything starts with a digit sequence
|
|
( ( {(LA(2)!='.')&&(LA(2)!=')')}? // force k=2; avoid ".."
|
|
//PSPSPS example ARRAY (.1..99.) OF char; // after .. thinks it's a NUM_REAL
|
|
'.' {$setType(NUM_REAL);} // dot means we are float
|
|
('0'..'9')+ (EXPONENT)?
|
|
)?
|
|
| EXPONENT {$setType(NUM_REAL);} // 'E' means we are float
|
|
)
|
|
;
|
|
|
|
// a couple protected methods to assist in matching floating point numbers
|
|
protected
|
|
EXPONENT
|
|
: ('e') ('+'|'-')? ('0'..'9')+
|
|
;
|