%{
use strict;
use warnings;
our $VERSION = 0.000_910;
use Carp;
use rperlrules; # affirmative, it totally does
%}
%strict # require all tokens to be declared, etc.
%tree # automatically create AST
%whites /((?:\s*(?:#[^#!].*)?\s*)*)/ # actual whitespace, or one or more normal comments; neither shebang '#!', nor double-hash critics '##'
%defaultaction {
my $self = shift;
my $name = $self->YYName();
bless { children => [ @_ ] }, $name;
}
%token SHEBANG = /(^#!\/(?:\w+\/)*perl)/ # begin line, hash (octothorpe), bang, *NIX path to Perl; ex. '#!/usr/bin/perl'
%token VERSION_NUMBER_ASSIGN = /\$VERSION\ =\ (\d\d?\.\d{3}\_\d{3});/ # match assign match, only capture & return number; ex. '$VERSION = 12.345_678;' returns '12.345_678'
%token LITERAL_NUMBER = /(-?(((\d{1,2}_)?(\d{3}_)*\d{3})|\d{1,2})(\.((\d{3}(_\d{3})*(_\d{1,2})?)|\d{1,2}))?)/ # number w/ underscores; ex. '12_345_678.910_1'
%token LITERAL_STRING = /(('[^']+')|("[^"\@\$]*((\\n)|(\\t))+[^"\@\$]*")|(q{[^}]*}))/ # single quotes non-empty; double quotes non-empty w/out sigils & w/ newline or tab; or single q-braces
%token FH_REF_SYMBOL_BRACES = /(\{\$[A-Z][A-Z0-9_]*\})/ # left brace, dollar sigil, uppercase letter, uppercase letters & numbers & underscores, right brace; ex. '{$MY_FILEHANDLE_23}'
%token FH_REF_SYMBOL = /(\$[A-Z][A-Z0-9_]*)/ # dollar sigil, uppercase letter, uppercase letters & numbers & underscores; ex. '$MY_FILEHANDLE_23'
%token VARIABLE_SYMBOL = /(\$[a-zA-Z]\w*(::)*\w*)/ # dollar sigil, scoped word
%token KEYS_OR_VALUES = /(keys|values)/
%token TYPE_CLASS_OR_SELF = /(string\s+\$class|object\s+\$self)/ # ex. 'string $class' or 'object $self'
%token STDOUT_STDERR = /(\{\*STDOUT\}|\{\*STDERR\})/ # '{*STDOUT}' or '{*STDERR}'
%token STDIN = /(<STDIN>)/ # '<STDIN>'
# FEATURE BOUNTY #000, 1_000 CodeCoin: Implement all Perl functions AKA builtins (PERLOPS_PERLTYPES) as C++ functions (CPPOPS_PERLTYPES & CPPOPS_CPPTYPES)
# Affects OP01_NAMED, OP01_NAMED_VOID, and OP10_NAMED_UNARY below, corresponding RPerl::Test::Operator* and C++ code; http://perldoc.perl.org/perlfunc.html
# PRECEDENCE, LEXICAL ORDERING: earlier declaration gets tried first; http://perldoc.perl.org/perlop.html#Operator-Precedence-and-Associativity [1]
%token OP24_LOGICAL_OR_XOR = /(or|xor)/ # precedence 24 infix: logical or and xor, equivalent to || except for precedence
%token OP23_LOGICAL_AND = /(and)/ # precedence 23 infix: logical and, equivalent to && except for precedence
%token OP22_LOGICAL_NEG = /(not)/ # precedence 22 prefix: logical negation, equivalent to ! except for precedence
%token OP21_LIST_COMMA = /(,)/ # precedence 21 infix: "list operators (rightward)" [1] AKA comma
%token OP20_HASH_FATARROW = /(=>)/ # precedence 20 infix: hash entry fat arrow AKA fat comma
%token OP19_LOOP_CONTROL = /(next|last)/ # precedence 19 prefix void: loop control next, last
%token OP18_TERNARY = /(\?)/ # precedence 18 infix: ternary conditional
%token OP17_LIST_RANGE = /(\.\.)/ # precedence 17 infix: range
%token OP16_LOGICAL_OR = /(\|\|)/ # precedence 16 infix: logical or
%token OP15_LOGICAL_AND = /(&&)/ # precedence 15 infix: logical and
%token OP14_BITWISE_OR_XOR = /(\||\^)/ # precedence 14 infix: bitwise or, bitwise xor
%token OP13_BITWISE_AND = /(&)/ # precedence 13 infix: bitwise and
%token OP12_COMPARE_EQ_NE = /(==|!=|eq|ne)/ # precedence 12 infix: comparison numeric equal, numeric not equal, string equal, string not equal
%token OP09_BITWISE_SHIFT = /(<<|>>)/ # precedence 09 infix: bitwise shift left, shift right
%token OP10_NAMED_UNARY = /(chdir|rand|scalar[^t])/ # precedence 10 prefix: "named unary operators" [1]; ex. 'chdir' and 'rand'; 'scalar' not 'scalartype'
%token OP10_STRINGIFY_UNARY = /((?:main)?::[a-zA-Z]\w*__stringify\()/ # precedence 10 prefix: stringify AKA pretty print; ex. '::integer__array_ref__stringify'
%token OP08_STRING_CAT = /(\.)/ # precedence 08 infix: string concatenate
%token OP03_MATH_INC_DEC = /(\+\+|--)/ # precedence 03 prefix and postfix: increment, decrement
%token OP04_MATH_POW = /(\*\*)/ # precedence 04 infix: arithmetic exponent AKA power
%token OP07_MATH_MULT_DIV_MOD = /(\*|\/|\%)/ # precedence 07 infix: arithmetic multiply, divide, modulo
%token OP06_REGEX_PATTERN = /([ms]\/.*(?:\/.*)?\/[a-z]*)/ # precedence 06 infix: regular expression pattern
%token OP06_REGEX_MATCH = /(=\~|!\~)/ # precedence 06 infix: regular expression match, not match
%token OP19_VARIABLE_ASSIGN_BY = /(\+=|-=|\*=|\/=)/ # precedence 19 infix: add assign, subtract assign, multiply assign, divide assign
%token OP05_LOGICAL_NEG = /(!)/ # precedence 05 prefix: logical negation
%token OP02_HASH_THINARROW = /(->\{)/ # precedence 02 infix: thin arrow, hash dereference and retrieval
%token OP02_ARRAY_THINARROW = /(->\[)/ # precedence 02 infix: thin arrow, array dereference and retrieval
%token OP02_METHOD_THINARROW = /(->)/ # precedence 02 infix: thin arrow, method dereference and call
%token OP05_MATH_NEG_LPAREN = /(-\()/ # precedence 05 prefix: arithmetic negative
%token OP08_MATH_ADD_SUB = /(\+|-)/ # precedence 08 infix: arithmetic add, subtract
%token OP11_COMPARE_LT_GT = /(<=|>=|<|>|lt|gt|le|ge)/ # precedence 11 infix: comparison less than, greater than, less or equal, greater or equal
%token OP19_VARIABLE_ASSIGN = /(=)/ # precedence 19 infix: assign
%token OP01_PRINT = /(print)/ # precedence 01 prefix void: print to STDOUT, STDERR, or filehandle
%token OP01_NAMED_VOID = /(croak|return|exit)/ # precedence 01 prefix void: "terms and list operators (leftward)" [1] AKA builtins, no return value
%token OP01_QW = /(qw)/ # precedence 01 prefix: quoted words
%token OP01_OPEN = /(open)/ # precedence 01 prefix: open filehandle
%token OP01_CLOSE = /(close)/ # precedence 01 prefix: close filehandle
%token OP01_NAMED = /(sin|cos|push|pop|ETC)/ # precedence 01 prefix: "terms and list operators (leftward)" [1] AKA builtins
# PRECEDENCE, SYNTAX ASSOCIATIVITY: later declaration gets higher priority
%left OP24_LOGICAL_OR_XOR
%left OP23_LOGICAL_AND
%right OP22_LOGICAL_NEG
%left OP21_LIST_COMMA
%left OP20_HASH_FATARROW
%right OP19_LOOP_CONTROL
%right OP19_VARIABLE_ASSIGN_BY
%right OP19_VARIABLE_ASSIGN
%right OP18_TERNARY
%nonassoc OP17_LIST_RANGE
%left OP16_LOGICAL_OR
%left OP15_LOGICAL_AND
%left OP14_BITWISE_OR_XOR
%left OP13_BITWISE_AND
%nonassoc OP12_COMPARE_EQ_NE
%nonassoc OP11_COMPARE_LT_GT
%nonassoc OP10_NAMED_UNARY
%nonassoc OP10_STRINGIFY_UNARY
%left OP09_BITWISE_SHIFT
%left OP08_STRING_CAT
%left OP08_MATH_ADD_SUB
%left OP07_MATH_MULT_DIV_MOD
%left OP06_REGEX_MATCH
%left OP06_REGEX_PATTERN
%right OP05_MATH_NEG_LPAREN
%right OP05_LOGICAL_NEG
%right OP04_MATH_POW
%nonassoc OP03_MATH_INC_DEC
%left OP02_HASH_THINARROW
%left OP02_ARRAY_THINARROW
%left OP02_METHOD_THINARROW
%left OP01_NAMED
%left OP01_CLOSE
%left OP01_OPEN
%left OP01_QW
%left OP01_NAMED_VOID
%left OP01_PRINT
%token TYPE_METHOD = /([a-zA-Z]\w*__method)/ # letter followed by letters, numbers, and underscores, followed by '__method'; ex. 'string__array_ref__method'
%token WORD_SCOPED = /(([a-zA-Z]\w*(::[a-zA-Z]\w*)+)|(::[a-zA-Z]\w*(::[a-zA-Z]\w*)*))/
%token WORD = /([a-zA-Z]\w*)/ # letter followed by letters, numbers, and underscores; ex. 'foobar_42_Howdy'
%token COLON = /:/
%token LPAREN = /\(/
%token LBRACKET = /\[/
%token LBRACE = /\{/
%%
CompileUnit: Program | (ModuleHeader Module)+ ;
Program: SHEBANG Critic? Header Critic* Include* Constant* Subroutine* Operation+ ;
ModuleHeader: Critic? 'package' WordScoped ';' Header ;
Module: Package | Class ;
Package: Critic* Include* Constant* Subroutine+ LITERAL_NUMBER ';' ;
Header: 'use strict;' 'use warnings;' 'use RPerl;' 'our' VERSION_NUMBER_ASSIGN;
Critic: '## no critic qw(' WORD+ ')';
Include: 'use' WordScoped ';' | 'use' WordScoped 'qw(' WORD+ ')' ';' ;
Constant: 'use constant' WORD OP20_HASH_FATARROW TypeInner Literal ';' ;
#Constant: 'use constant' WORD OP20_HASH_FATARROW TypeInner ConstantValue ';' ; # NEED UPGRADE: constant array & hash refs not read-only as of Perl v5.20
#ConstantValue: Literal | LBRACKET TypeInner? Literal (OP21_LIST_COMMA TypeInner? Literal)* ']' |
# LBRACE WORD OP20_HASH_FATARROW TypeInner? Literal (OP21_LIST_COMMA WORD OP20_HASH_FATARROW TypeInner? Literal)* '}' ;
Subroutine: 'our' Type VARIABLE_SYMBOL '= sub {' SubroutineArguments? Operation+ '}' ';' ;
SubroutineArguments: '( my' Type VARIABLE_SYMBOL (OP21_LIST_COMMA 'my' Type VARIABLE_SYMBOL)* ')' OP19_VARIABLE_ASSIGN '@_;' ;
Class: 'use parent qw(' WordScoped ')' ';' Include Critic* Include* Constant* Properties PropertiesClass? MethodOrSubroutine* LITERAL_NUMBER ';' ;
Properties: 'our %properties = (' Critic HashEntryTyped (OP21_LIST_COMMA HashEntryTyped)* ')' ';' | 'our %properties = (' ')' ';' Critic ;
PropertiesClass: 'our %properties_class = (' Critic HashEntryTyped (OP21_LIST_COMMA HashEntryTyped)* ')' ';' ;
Method: 'our' TYPE_METHOD VARIABLE_SYMBOL '= sub {' MethodArguments? Operation+ '}' ';' ;
MethodArguments: '( my' TYPE_CLASS_OR_SELF (OP21_LIST_COMMA 'my' Type VARIABLE_SYMBOL)* ')' OP19_VARIABLE_ASSIGN '@_;' ;
MethodOrSubroutine: Method | Subroutine;
Operation: Expression ';' | Statement ;
Operator: LPAREN OP01_PRINT FH_REF_SYMBOL_BRACES ListElements ')' |
OP01_NAMED SubExpression | LPAREN OP01_NAMED ListElement OP21_LIST_COMMA ListElements ')' |
OP01_OPEN 'my' 'filehandle_ref' FH_REF_SYMBOL OP21_LIST_COMMA LITERAL_STRING OP21_LIST_COMMA SubExpression |
OP01_CLOSE FH_REF_SYMBOL | OP03_MATH_INC_DEC Variable | Variable OP03_MATH_INC_DEC | SubExpression OP04_MATH_POW SubExpression |
OP05_LOGICAL_NEG SubExpression | OP05_MATH_NEG_LPAREN SubExpression ')' | SubExpression OP06_REGEX_MATCH OP06_REGEX_PATTERN |
SubExpression OP07_MATH_MULT_DIV_MOD SubExpression | SubExpression OP08_MATH_ADD_SUB SubExpression |
SubExpression OP08_STRING_CAT SubExpression | SubExpression OP09_BITWISE_SHIFT SubExpression | OP10_NAMED_UNARY SubExpression |
OP10_NAMED_UNARY | OP10_STRINGIFY_UNARY SubExpression ')' | SubExpression OP11_COMPARE_LT_GT SubExpression |
SubExpression OP12_COMPARE_EQ_NE SubExpression | SubExpression OP13_BITWISE_AND SubExpression |
SubExpression OP14_BITWISE_OR_XOR SubExpression | SubExpression OP15_LOGICAL_AND SubExpression | SubExpression OP16_LOGICAL_OR SubExpression |
SubExpression OP17_LIST_RANGE SubExpression | SubExpression OP18_TERNARY VariableOrLiteral COLON VariableOrLiteral |
OP22_LOGICAL_NEG SubExpression | SubExpression OP23_LOGICAL_AND SubExpression | SubExpression OP24_LOGICAL_OR_XOR SubExpression ;
OperatorVoid: OP01_PRINT (STDOUT_STDERR)? ListElements ';' | OP01_PRINT FH_REF_SYMBOL_BRACES ListElements ';' |
OP01_NAMED_VOID ListElements? ';' | OP01_NAMED ListElement OP21_LIST_COMMA ListElements ';' | OP19_LOOP_CONTROL LoopLabel ';' ;
Expression: Operator | WordScoped LPAREN ListElements? ')' | Variable OP02_METHOD_THINARROW WORD LPAREN ListElements? ')' ;
SubExpression: Expression | 'undef' | Literal | Variable | ArrayReference | ArrayDereferenced | HashReference | HashDereferenced | LBRACE '}' |
LPAREN SubExpression ')' ;
SubExpressionOrStdin: SubExpression | STDIN;
Statement: Conditional | (LoopLabel COLON)? Loop | OperatorVoid | VariableDeclaration | VariableModification ;
Conditional: 'if (' SubExpression ')' CodeBlock ('elsif (' SubExpression ')' CodeBlock)* ('else' CodeBlock)? ;
Loop: LoopFor | LoopForEach | LoopWhile ;
LoopFor: 'for my integer' VARIABLE_SYMBOL LPAREN SubExpression OP17_LIST_RANGE SubExpression ')' CodeBlock ;
LoopForEach: 'foreach my' Type VARIABLE_SYMBOL LPAREN ListElements ')' CodeBlock ;
LoopWhile: 'while (' SubExpression ')' CodeBlock ;
CodeBlock: LBRACE Operation+ '}' ;
Variable: VARIABLE_SYMBOL VariableRetrieval* ;
VariableRetrieval: OP02_ARRAY_THINARROW SubExpression ']' | OP02_HASH_THINARROW SubExpression '}' | OP02_HASH_THINARROW WORD '}' ;
VariableDeclaration: 'my' Type VARIABLE_SYMBOL ';' | 'my' Type VARIABLE_SYMBOL OP19_VARIABLE_ASSIGN SubExpressionOrStdin ';' ;
VariableModification: Variable OP19_VARIABLE_ASSIGN SubExpressionOrStdin ';' | Variable OP19_VARIABLE_ASSIGN_BY SubExpression ';' ;
ListElements: ListElement (OP21_LIST_COMMA ListElement)* | OP01_QW LPAREN WORD+ ')' ;
ListElement: SubExpression | TypeInner SubExpression | KEYS_OR_VALUES HashDereferenced ;
ArrayReference: LBRACKET ListElements? ']' ;
ArrayDereferenced: '@{' Variable '}' | '@{' ArrayReference '}' ;
HashEntry: WORD OP20_HASH_FATARROW TypeInner? SubExpression | HashDereferenced ;
HashEntryTyped: WORD OP20_HASH_FATARROW TypeInner SubExpression | HashDereferenced ;
HashReference: LBRACE HashEntry (OP21_LIST_COMMA HashEntry)* '}' ;
HashDereferenced: '%{' Variable '}' | '%{' HashReference '}' ;
WordScoped: WORD | WORD_SCOPED;
LoopLabel: WORD ;
Type: WORD ;
TypeInner: 'my' Type '$TYPED_' WORD OP19_VARIABLE_ASSIGN ;
VariableOrLiteral: Variable | Literal;
Literal: LITERAL_STRING | LITERAL_NUMBER ;
%%
{
# Rules from Grammar.output
# NEED FIX: UPDATE!?!
my string__hash_ref $rules = {
CompileUnit_3 => 'RPerl::CompileUnit',
CompileUnit_4 => 'RPerl::CompileUnit',
Program_9 => 'RPerl::CompileUnit::Program',
Module_10 => 'RPerl::CompileUnit::Module',
Module_11 => 'RPerl::CompileUnit::Module',
Package_14 => 'RPerl::CompileUnit::Module::Package',
Subroutine_38 => 'RPerl::CodeBlock::Subroutine',
Class_52 => 'RPerl::CompileUnit::Module::Class',
Properties_55 => 'RPerl::DataStructure::Hash::Properties',
Method_60 => 'RPerl::CodeBlock::Subroutine::Method',
Operation_65 => 'RPerl::Operation',
Operation_66 => 'RPerl::Operation',
Operator_69 => 'RPerl::Operation::Expression::Operator',
};
1;
}