use
constant
LHS_RESET_EVENT
=>
'<reset>'
;
use
constant
LHS_PROCESS_EVENT
=>
'<process>'
;
use
constant
CLOSEANYSCOPE_PRIORITY
=> -1000;
use
constant
RESETANYDATA_PRIORITY
=> -2000;
our
$VERSION
=
'0.12'
;
sub
new {
my
(
$class
,
$outerSelf
) =
@_
;
my
$self
=
$class
->SUPER();
if
(!
defined
(
$outerSelf
) ||
ref
(
$outerSelf
) ne
'MarpaX::Languages::C::AST'
) {
croak
'outerSelf must be a reference to MarpaX::Languages::C::AST'
;
}
$self
->hscratchpad(
'_impl'
,
$outerSelf
->{_impl});
$self
->hscratchpad(
'_scope'
,
$outerSelf
->{_scope});
$self
->hscratchpad(
'_sourcep'
,
$outerSelf
->{_sourcep});
my
@callbacks
= ();
push
(
@callbacks
,
$self
->_register_rule_callbacks({
lhs
=>
'declarationCheck'
,
rhs
=> [ [
'declarationCheckdeclarationSpecifiers'
, [
'storageClassSpecifierTypedef'
] ],
[
'declarationCheckinitDeclaratorList'
, [
'directDeclaratorIdentifier'
] ]
],
method
=> \
&_declarationCheck
,
counters
=> {
'structContext'
=> [
'structContextStart[]'
,
'structContextEnd[]'
]
},
process_priority
=> CLOSEANYSCOPE_PRIORITY - 1,
}
)
);
push
(
@callbacks
,
$self
->_register_rule_callbacks({
lhs
=>
'functionDefinitionCheck1'
,
rhs
=> [ [
'functionDefinitionCheck1declarationSpecifiers'
, [
'storageClassSpecifierTypedef'
] ],
[
'functionDefinitionCheck1declarationList'
, [
'storageClassSpecifierTypedef'
] ]
],
method
=> \
&_functionDefinitionCheck1
,
process_priority
=> CLOSEANYSCOPE_PRIORITY + 1,
}
)
);
push
(
@callbacks
,
$self
->_register_rule_callbacks({
lhs
=>
'functionDefinitionCheck2'
,
rhs
=> [ [
'functionDefinitionCheck2declarationSpecifiers'
, [
'storageClassSpecifierTypedef'
] ],
],
method
=> \
&_functionDefinitionCheck2
,
process_priority
=> CLOSEANYSCOPE_PRIORITY + 1,
}
)
);
push
(
@callbacks
,
$self
->_register_rule_callbacks({
lhs
=>
'parameterDeclarationCheck'
,
rhs
=> [ [
'parameterDeclarationdeclarationSpecifiers'
, [
'storageClassSpecifierTypedef'
] ]
],
method
=> \
&_parameterDeclarationCheck
,
}
)
);
$self
->register(MarpaX::Languages::C::AST::Callback::Method->new
(
description
=>
'enumerationConstantIdentifier$'
,
method
=> [ \
&_enumerationConstantIdentifier
],
option
=> MarpaX::Languages::C::AST::Callback::Option->new
(
condition
=> [ [
'auto'
] ],
)
)
);
$self
->hscratchpad(
'_scope'
)->parseEnterScopeCallback(\
&_enterScopeCallback
,
$self
,
@callbacks
);
$self
->hscratchpad(
'_scope'
)->parseExitScopeCallback(\
&_exitScopeCallback
,
$self
,
@callbacks
);
$self
->register(MarpaX::Languages::C::AST::Callback::Method->new
(
description
=>
'fileScopeDeclarator$'
,
method
=> [ \
&_set_helper
,
'fileScopeDeclarator'
, 1,
'reenterScope'
, 0 ],
method_void
=> 1,
option
=> MarpaX::Languages::C::AST::Callback::Option->new
(
condition
=> [
[
'auto'
],
[
sub
{
my
(
$method
,
$callback
,
$eventsp
,
$scope
) =
@_
;
return
(
$scope
->parseScopeLevel == 0);
},
$self
->hscratchpad(
'_scope'
)
]
],
topic
=> {
'fileScopeDeclarator'
=> 1,
'reenterScope'
=> 1},
topic_persistence
=>
'any'
,
)
)
);
$self
->register(MarpaX::Languages::C::AST::Callback::Method->new
(
description
=>
'^externalDeclaration'
,
method
=> [ \
&_closeAnyScope
,
$self
->hscratchpad(
'_scope'
) ],
option
=> MarpaX::Languages::C::AST::Callback::Option->new
(
condition
=> [ [
'auto'
] ],
priority
=> CLOSEANYSCOPE_PRIORITY
)
)
);
$self
->register(MarpaX::Languages::C::AST::Callback::Method->new
(
description
=>
'^externalDeclaration'
,
method
=> [ \
&_resetAnyData
,
@callbacks
],
option
=> MarpaX::Languages::C::AST::Callback::Option->new
(
condition
=> [ [
'auto'
] ],
priority
=> RESETANYDATA_PRIORITY
)
)
);
return
$self
;
}
sub
_closeAnyScope {
my
(
$method
,
$callback
,
$eventsp
,
$scope
) =
@_
;
while
(
$scope
->parseScopeLevel >= 1) {
$scope
->doExitScope();
}
}
sub
_resetAnyData {
my
(
$method
,
$callback
,
$eventsp
,
@callbacks
) =
@_
;
foreach
(
@callbacks
) {
$_
->
exec
(LHS_RESET_EVENT);
}
}
sub
_enumerationConstantIdentifier {
my
(
$method
,
$callback
,
$eventsp
) =
@_
;
my
$enum
= lastCompleted(
$callback
->hscratchpad(
'_impl'
),
'enumerationConstantIdentifier'
);
$callback
->hscratchpad(
'_scope'
)->parseEnterEnum(
$enum
);
}
sub
_parameterDeclarationCheck {
my
(
$method
,
$callback
,
$eventsp
) =
@_
;
my
$parameterDeclarationdeclarationSpecifiers
=
$callback
->topic_level_fired_data(
'parameterDeclarationdeclarationSpecifiers$'
);
my
$nbTypedef
= $
if
(
$nbTypedef
>= 0) {
my
(
$line_columnp
,
$last_completed
) = @{
$parameterDeclarationdeclarationSpecifiers
->[0]};
logCroak(
"[%s[%d]] %s is not valid in a parameter declaration\n%s\n"
, whoami(__PACKAGE__),
$callback
->currentTopicLevel,
$last_completed
, showLineAndCol(@{
$line_columnp
},
$callback
->hscratchpad(
'_sourcep'
)));
}
}
sub
_functionDefinitionCheck1 {
my
(
$method
,
$callback
,
$eventsp
) =
@_
;
my
$functionDefinitionCheck1declarationSpecifiers
=
$callback
->topic_level_fired_data(
'functionDefinitionCheck1declarationSpecifiers$'
, -1);
my
$functionDefinitionCheck1declarationList
=
$callback
->topic_fired_data(
'functionDefinitionCheck1declarationList$'
);
my
$nbTypedef1
= $
if
(
$nbTypedef1
>= 0) {
my
(
$line_columnp
,
$last_completed
) = @{
$functionDefinitionCheck1declarationSpecifiers
->[0]};
logCroak(
"[%s[%d]] %s is not valid in a function declaration specifier\n%s\n"
, whoami(__PACKAGE__),
$callback
->currentTopicLevel,
$last_completed
, showLineAndCol(@{
$line_columnp
},
$callback
->hscratchpad(
'_sourcep'
)));
}
my
$nbTypedef2
= $
if
(
$nbTypedef2
>= 0) {
my
(
$line_columnp
,
$last_completed
) = @{
$functionDefinitionCheck1declarationList
->[0]};
logCroak(
"[%s[%d]] %s is not valid in a function declaration list\n%s\n"
, whoami(__PACKAGE__),
$callback
->currentTopicLevel,
$last_completed
, showLineAndCol(@{
$line_columnp
},
$callback
->hscratchpad(
'_sourcep'
)));
}
}
sub
_functionDefinitionCheck2 {
my
(
$method
,
$callback
,
$eventsp
) =
@_
;
my
$functionDefinitionCheck2declarationSpecifiers
=
$callback
->topic_level_fired_data(
'functionDefinitionCheck2declarationSpecifiers$'
, -1);
my
$nbTypedef
= $
if
(
$nbTypedef
>= 0) {
my
(
$line_columnp
,
$last_completed
) = @{
$functionDefinitionCheck2declarationSpecifiers
->[0]};
logCroak(
"[%s[%d]] %s is not valid in a function declaration specifier\n%s\n"
, whoami(__PACKAGE__),
$callback
->currentTopicLevel,
$last_completed
, showLineAndCol(@{
$line_columnp
},
$callback
->hscratchpad(
'_sourcep'
)));
}
}
sub
_declarationCheck {
my
(
$method
,
$callback
,
$eventsp
) =
@_
;
my
$structContext
=
$callback
->topic_fired_data(
'structContext'
) || [0];
if
(
$structContext
->[0]) {
return
;
}
my
$declarationCheckdeclarationSpecifiers
=
$callback
->topic_fired_data(
'declarationCheckdeclarationSpecifiers$'
);
my
$declarationCheckinitDeclaratorList
=
$callback
->topic_fired_data(
'declarationCheckinitDeclaratorList$'
);
my
$nbTypedef
= $
if
(
$nbTypedef
> 0) {
my
(
$line_columnp
,
$last_completed
) = @{
$declarationCheckdeclarationSpecifiers
->[1]};
logCroak(
"[%s[%d]] %s cannot appear more than once\n%s\n"
, whoami(__PACKAGE__),
$callback
->currentTopicLevel,
$last_completed
, showLineAndCol(@{
$line_columnp
},
$callback
->hscratchpad(
'_sourcep'
)));
}
foreach
(@{
$declarationCheckinitDeclaratorList
}) {
my
(
$line_columnp
,
$last_completed
,
%counters
) = @{
$_
};
if
(!
$counters
{structContext}) {
if
(
$nbTypedef
>= 0) {
$callback
->hscratchpad(
'_scope'
)->parseEnterTypedef(
$last_completed
);
}
else
{
$callback
->hscratchpad(
'_scope'
)->parseObscureTypedef(
$last_completed
);
}
}
}
}
sub
_enterScopeCallback {
foreach
(
@_
) {
$_
->pushTopicLevel();
}
}
sub
_exitScopeCallback {
foreach
(
@_
) {
$_
->popTopicLevel();
}
}
sub
_storage_helper {
my
(
$method
,
$callback
,
$eventsp
,
$event
,
$countersHashp
) =
@_
;
my
%counters
= ();
foreach
(
keys
%{
$countersHashp
}) {
my
$counterDatap
=
$callback
->topic_fired_data(
$_
) || [0];
$counters
{
$_
} =
$counterDatap
->[0] || 0;
}
my
$symbol
=
$event
;
my
$rc
;
if
(
substr
(
$symbol
, 0, 1) eq
'^'
) {
substr
(
$symbol
, 0, 1,
''
);
$rc
= [ lineAndCol(
$callback
->hscratchpad(
'_impl'
)),
%counters
];
}
elsif
(
substr
(
$symbol
, -1, 1) eq
'$'
) {
substr
(
$symbol
, -1, 1,
''
);
$rc
= [ lineAndCol(
$callback
->hscratchpad(
'_impl'
)), lastCompleted(
$callback
->hscratchpad(
'_impl'
),
$symbol
),
%counters
];
}
return
$rc
;
}
sub
_inc_helper {
my
(
$method
,
$callback
,
$eventsp
,
$topic
,
$increment
) =
@_
;
my
$old_value
=
$callback
->topic_fired_data(
$topic
)->[0] || 0;
my
$new_value
=
$old_value
+
$increment
;
return
$new_value
;
}
sub
_set_helper {
my
(
$method
,
$callback
,
$eventsp
,
%topic
) =
@_
;
foreach
(
keys
%topic
) {
$callback
->topic_fired_data(
$_
, [
$topic
{
$_
} ]);
}
}
sub
_reset_helper {
my
(
$method
,
$callback
,
$eventsp
,
@topics
) =
@_
;
my
@rc
= ();
return
@rc
;
}
sub
_collect_helper {
my
(
$method
,
$callback
,
$eventsp
,
@topics
) =
@_
;
my
@rc
= ();
foreach
(
@topics
) {
my
$topic
=
$_
;
push
(
@rc
, @{
$callback
->topic_fired_data(
$topic
)});
$callback
->topic_fired_data(
$topic
, []);
}
return
@rc
;
}
sub
_subFire {
my
(
$method
,
$callback
,
$eventsp
,
$lhs
,
$subCallback
,
$filterEventsp
,
$transformEventsp
) =
@_
;
my
@subEvents
=
grep
{
exists
(
$filterEventsp
->{
$_
})} @{
$eventsp
};
if
(
@subEvents
) {
if
(
defined
(
$transformEventsp
)) {
my
%tmp
= ();
my
@transformEvents
=
grep
{++
$tmp
{
$_
} == 1}
map
{
$transformEventsp
->{
$_
} ||
$_
}
@subEvents
;
$subCallback
->
exec
(
@transformEvents
);
}
else
{
$subCallback
->
exec
(
@subEvents
);
}
}
}
sub
_register_rule_callbacks {
my
(
$self
,
$hashp
) =
@_
;
my
$callback
= MarpaX::Languages::C::AST::Callback->new(
log_prefix
=>
' '
.
$hashp
->{lhs} .
' '
);
$callback
->hscratchpad(
'_impl'
,
$self
->hscratchpad(
'_impl'
));
$callback
->hscratchpad(
'_scope'
,
$self
->hscratchpad(
'_scope'
));
$callback
->hscratchpad(
'_sourcep'
,
$self
->hscratchpad(
'_sourcep'
));
my
%rshProcessEvents
= ();
my
$countersHashp
=
$hashp
->{counters} || {};
foreach
(
keys
%{
$countersHashp
}) {
my
$counter
=
$_
;
my
(
$eventStart
,
$eventEnd
) = @{
$countersHashp
->{
$counter
}};
++
$rshProcessEvents
{
$eventStart
};
$callback
->register(MarpaX::Languages::C::AST::Callback::Method->new
(
description
=>
$eventStart
,
extra_description
=>
$counter
.
' [Start] '
,
method
=> [ \
&_inc_helper
,
$counter
, 1 ],
method_mode
=>
'replace'
,
option
=> MarpaX::Languages::C::AST::Callback::Option->new
(
topic
=> {
$counter
=> 1},
topic_persistence
=>
'any'
,
condition
=> [ [
'auto'
] ],
priority
=> 999,
)
)
);
++
$rshProcessEvents
{
$eventEnd
};
$callback
->register(MarpaX::Languages::C::AST::Callback::Method->new
(
description
=>
$eventEnd
,
extra_description
=>
$counter
.
' [End] '
,
method
=> [ \
&_inc_helper
,
$counter
, -1 ],
method_mode
=>
'replace'
,
option
=> MarpaX::Languages::C::AST::Callback::Option->new
(
topic
=> {
$counter
=> 1},
topic_persistence
=>
'any'
,
condition
=> [ [
'auto'
] ],
priority
=> 999,
)
)
);
}
my
%genomeEvents
= ();
foreach
(@{
$hashp
->{rhs}}) {
my
(
$rhs
,
$genomep
) = @{
$_
};
foreach
(@{
$genomep
}) {
my
$event
=
$_
.
'$'
;
++
$genomeEvents
{
$event
};
++
$rshProcessEvents
{
$event
};
}
}
foreach
(
keys
%genomeEvents
) {
$callback
->register(MarpaX::Languages::C::AST::Callback::Method->new
(
description
=>
$_
,
extra_description
=>
"$_ [storage] "
,
method
=> [ \
&_storage_helper
,
$_
,
$countersHashp
],
option
=> MarpaX::Languages::C::AST::Callback::Option->new
(
topic
=> {
$_
=> 1},
topic_persistence
=>
'level'
,
condition
=> [ [
'auto'
] ],
priority
=> 999,
)
)
);
}
my
$i
= 0;
my
%rhsTopicsToUpdate
= ();
my
%rhsTopicsNotToUpdate
= ();
foreach
(@{
$hashp
->{rhs}}) {
my
(
$rhs
,
$genomep
) = @{
$_
};
my
$rhsTopic
=
$rhs
.
'$'
;
$rhsTopicsToUpdate
{
$rhsTopic
} = 1;
$rhsTopicsNotToUpdate
{
$rhsTopic
} = -1;
my
%genomeTopicsToUpdate
= ();
my
%genomeTopicsNotToUpdate
= ();
foreach
(@{
$genomep
}) {
$genomeTopicsToUpdate
{
$_
.
'$'
} = 1;
$genomeTopicsNotToUpdate
{
$_
.
'$'
} = -1;
}
my
$event
=
$rhs
.
'$'
;
++
$rshProcessEvents
{
$event
};
$callback
->register(MarpaX::Languages::C::AST::Callback::Method->new
(
description
=>
$event
,
extra_description
=>
"$event [process] "
,
method
=> [ \
&_collect_helper
,
keys
%genomeTopicsNotToUpdate
],
method_mode
=>
'push'
,
option
=> MarpaX::Languages::C::AST::Callback::Option->new
(
condition
=> [ [
'auto'
] ],
topic
=> {
$rhsTopic
=> 1,
%genomeTopicsNotToUpdate
},
topic_persistence
=>
'level'
,
priority
=> 1,
)
)
);
$callback
->register(MarpaX::Languages::C::AST::Callback::Method->new
(
description
=>
$event
,
extra_description
=>
"$event [reset] "
,
method
=> [ \
&_reset_helper
,
keys
%genomeTopicsToUpdate
],
method_mode
=>
'replace'
,
option
=> MarpaX::Languages::C::AST::Callback::Option->new
(
condition
=> [ [
'auto'
] ],
topic
=> {
%genomeTopicsToUpdate
},
topic_persistence
=>
'level'
,
priority
=> 0,
)
)
);
}
my
$lhsProcessEvent
= LHS_PROCESS_EVENT;
my
%lhsProcessEvents
= (
$hashp
->{lhs} .
'$'
=> 1);
my
$lhsResetEvent
= LHS_RESET_EVENT;
my
%lhsResetEvents
= (
$hashp
->{lhs} .
'$'
=> 1,
'translationUnit$'
=> 1);
$callback
->register(MarpaX::Languages::C::AST::Callback::Method->new
(
description
=>
$lhsProcessEvent
,
method
=> [
$hashp
->{method} ],
option
=> MarpaX::Languages::C::AST::Callback::Option->new
(
condition
=> [ [
'auto'
] ],
topic
=> \
%rhsTopicsNotToUpdate
,
topic_persistence
=>
'level'
,
priority
=> 1,
)
)
);
$callback
->register(MarpaX::Languages::C::AST::Callback::Method->new
(
description
=>
$lhsResetEvent
,
method
=> [ \
&_reset_helper
,
keys
%rhsTopicsToUpdate
],
method_mode
=>
'replace'
,
option
=> MarpaX::Languages::C::AST::Callback::Option->new
(
condition
=> [ [
'auto'
] ],
topic
=> \
%rhsTopicsToUpdate
,
topic_persistence
=>
'level'
,
priority
=> 0,
)
)
);
$self
->register(MarpaX::Languages::C::AST::Callback::Method->new
(
description
=>
$hashp
->{lhs} .
' [intermediary events]'
,
method
=> [ \
&_subFire
,
$hashp
->{lhs},
$callback
, \
%rshProcessEvents
],
option
=> MarpaX::Languages::C::AST::Callback::Option->new
(
condition
=> [
[
sub
{
my
(
$method
,
$callback
,
$eventsp
,
$processEventsp
) =
@_
;
return
grep
{
exists
(
$processEventsp
->{
$_
})} @{
$eventsp
};
},
\
%rshProcessEvents
]
],
)
)
);
$self
->register(MarpaX::Languages::C::AST::Callback::Method->new
(
description
=>
$lhsProcessEvent
,
method
=> [ \
&_subFire
,
$hashp
->{lhs},
$callback
, \
%lhsProcessEvents
, {
$hashp
->{lhs} .
'$'
=>
$lhsProcessEvent
} ],
option
=> MarpaX::Languages::C::AST::Callback::Option->new
(
condition
=> [
[
sub
{
my
(
$method
,
$callback
,
$eventsp
,
$processEventsp
) =
@_
;
return
grep
{
exists
(
$processEventsp
->{
$_
})} @{
$eventsp
};
},
\
%lhsProcessEvents
]
],
priority
=>
$hashp
->{process_priority} || 0
)
)
);
return
$callback
;
}
1;
Hide Show 43 lines of Pod