Parser - Some clean-up in previously added code
This commit is contained in:
parent
84cdfa38de
commit
5d3aa32e9d
1 changed files with 112 additions and 94 deletions
206
opparser.cc
206
opparser.cc
|
@ -169,6 +169,9 @@ struct T_ParserImpl_
|
||||||
|
|
||||||
void main( T_SRDList const& list ) noexcept;
|
void main( T_SRDList const& list ) noexcept;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
|
||||||
|
private:
|
||||||
bool checkRequiredBlocks( T_SRDList const& list ) noexcept;
|
bool checkRequiredBlocks( T_SRDList const& list ) noexcept;
|
||||||
bool checkCalls( ) noexcept;
|
bool checkCalls( ) noexcept;
|
||||||
bool checkInstructionRestrictions( ) noexcept;
|
bool checkInstructionRestrictions( ) noexcept;
|
||||||
|
@ -177,6 +180,9 @@ struct T_ParserImpl_
|
||||||
bool checkArgumentTypes( ) noexcept;
|
bool checkArgumentTypes( ) noexcept;
|
||||||
bool checkIdentifierExpressions( ) noexcept;
|
bool checkIdentifierExpressions( ) noexcept;
|
||||||
|
|
||||||
|
E_DataType getTypeOf( T_String const& name ,
|
||||||
|
A_FuncNode const* context ) const noexcept;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
|
|
||||||
bool parseTopLevel( T_SRDList const& list ) noexcept;
|
bool parseTopLevel( T_SRDList const& list ) noexcept;
|
||||||
|
@ -386,60 +392,68 @@ bool T_ParserImpl_::checkInstructionRestrictions( ) noexcept
|
||||||
return true;
|
return true;
|
||||||
} );
|
} );
|
||||||
for ( auto i = 0u ; i < output->root.nFunctions( ) ; i ++ ) {
|
for ( auto i = 0u ; i < output->root.nFunctions( ) ; i ++ ) {
|
||||||
visitor.visit( output->root.function( i ) ,
|
visitor.visit( output->root.function( i ) , [&]( A_Node& node , bool exit ) {
|
||||||
[&]( A_Node& node , bool exit ) {
|
if ( exit ) {
|
||||||
if ( exit ) {
|
return false;
|
||||||
return false;
|
}
|
||||||
}
|
auto const* instr( dynamic_cast< A_InstructionNode const* >( &node ) );
|
||||||
auto const* instr( dynamic_cast< A_InstructionNode const* >( &node ) );
|
if ( instr && ( instr->restriction( ) & callInfo[ i ] ) ) {
|
||||||
if ( instr && ( instr->restriction( ) & callInfo[ i ] ) ) {
|
T_StringBuilder sb;
|
||||||
T_StringBuilder sb;
|
sb << "instruction not allowed in "
|
||||||
sb << "instruction not allowed in "
|
<< ( ( instr->restriction( ) & E_InstrRestriction::INIT )
|
||||||
<< ( ( instr->restriction( ) & E_InstrRestriction::INIT )
|
? "initialisation" : "frame function" );
|
||||||
? "initialisation" : "frame function" );
|
errors.addNew( std::move( sb ) , instr->location( ) );
|
||||||
errors.addNew( std::move( sb ) , instr->location( ) );
|
}
|
||||||
}
|
return true;
|
||||||
return true;
|
} );
|
||||||
} );
|
|
||||||
}
|
}
|
||||||
return errors.empty( );
|
return errors.empty( );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Find local variable declarations, add them to the function to owns them,
|
||||||
|
* add errors if duplicates or variables with names that match function
|
||||||
|
* arguments are found.
|
||||||
|
*/
|
||||||
bool T_ParserImpl_::checkLocalVariables( ) noexcept
|
bool T_ParserImpl_::checkLocalVariables( ) noexcept
|
||||||
{
|
{
|
||||||
uint32_t cfi;
|
uint32_t cfi;
|
||||||
T_StringBuilder esb;
|
T_StringBuilder esb;
|
||||||
for ( cfi = 0 ; cfi < output->root.nFunctions( ) ; cfi ++ ) {
|
for ( cfi = 0 ; cfi < output->root.nFunctions( ) ; cfi ++ ) {
|
||||||
auto& function( output->root.function( cfi ) );
|
auto& function( output->root.function( cfi ) );
|
||||||
visitor.visit( function ,
|
visitor.visit( function , [&]( A_Node& n , const bool exit ) -> bool {
|
||||||
[&]( A_Node& n , const bool exit ) -> bool {
|
if ( exit || n.type( ) != A_Node::OP_LOCALS ) {
|
||||||
if ( exit || n.type( ) != A_Node::OP_LOCALS ) {
|
return true;
|
||||||
return true;
|
}
|
||||||
|
|
||||||
|
auto& locals( dynamic_cast< T_LocalsInstrNode& >( n ) );
|
||||||
|
for ( auto i = 0u ; i < locals.variables( ) ; i ++ ) {
|
||||||
|
auto prev{ function.addLocalVariable(
|
||||||
|
locals.varName( i ) ,
|
||||||
|
locals.varLocation( i ) ) };
|
||||||
|
if ( !prev ) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& locals( dynamic_cast< T_LocalsInstrNode& >( n ) );
|
esb << "duplicate local '" << locals.varName( i )
|
||||||
for ( auto i = 0u ; i < locals.variables( ) ; i ++ ) {
|
<< "'; previous declaration at "
|
||||||
auto prev{ function.addLocalVariable(
|
<< *prev;
|
||||||
locals.varName( i ) ,
|
errors.addNew( std::move( esb ) , locals.varLocation( i ) );
|
||||||
locals.varLocation( i ) ) };
|
}
|
||||||
if ( !prev ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
esb << "duplicate local '" << locals.varName( i )
|
return false;
|
||||||
<< "'; previous declaration at "
|
} );
|
||||||
<< *prev;
|
|
||||||
errors.addNew( std::move( esb ) , locals.varLocation( i ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
} );
|
|
||||||
}
|
}
|
||||||
return errors.empty( );
|
return errors.empty( );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Find and determine the type of all global declarations. This includes
|
||||||
|
* variables and resources. In addition, make sure no resources are
|
||||||
|
* declared as local and that all declarations for a global name have
|
||||||
|
* the same type.
|
||||||
|
*/
|
||||||
bool T_ParserImpl_::collectGlobalTypes( ) noexcept
|
bool T_ParserImpl_::collectGlobalTypes( ) noexcept
|
||||||
{
|
{
|
||||||
|
// Temporary table for type / first declaration location
|
||||||
struct T_Decl_ {
|
struct T_Decl_ {
|
||||||
E_DataType type;
|
E_DataType type;
|
||||||
T_SRDLocation location;
|
T_SRDLocation location;
|
||||||
|
@ -467,13 +481,12 @@ bool T_ParserImpl_::collectGlobalTypes( ) noexcept
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the node defines or sets something, get its identifier,
|
||||||
|
// location and type.
|
||||||
E_DataType dt{ E_DataType::UNKNOWN };
|
E_DataType dt{ E_DataType::UNKNOWN };
|
||||||
T_String id;
|
T_String id;
|
||||||
T_SRDLocation location;
|
T_SRDLocation location;
|
||||||
if ( node.type( ) == A_Node::OP_SET ) {
|
if ( node.type( ) == A_Node::OP_SET ) {
|
||||||
// When we find a set instruction, we need to check whether
|
|
||||||
// it is affecting a local variable. If it is we'll just skip
|
|
||||||
// it.
|
|
||||||
id = dynamic_cast< T_SetInstrNode& >( node ).id( );
|
id = dynamic_cast< T_SetInstrNode& >( node ).id( );
|
||||||
dt = E_DataType::VARIABLE;
|
dt = E_DataType::VARIABLE;
|
||||||
location = dynamic_cast< T_SetInstrNode& >( node ).idLocation( );
|
location = dynamic_cast< T_SetInstrNode& >( node ).idLocation( );
|
||||||
|
@ -494,6 +507,9 @@ bool T_ParserImpl_::collectGlobalTypes( ) noexcept
|
||||||
esb.clear( );
|
esb.clear( );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// When we find a set instruction, we need to check whether
|
||||||
|
// it is affecting a local variable. If it is we'll just skip
|
||||||
|
// it.
|
||||||
if ( function.hasLocal( id ) ) {
|
if ( function.hasLocal( id ) ) {
|
||||||
if ( function.isArgument( id ) ) {
|
if ( function.isArgument( id ) ) {
|
||||||
errors.addNew( "trying to override argument",
|
errors.addNew( "trying to override argument",
|
||||||
|
@ -505,15 +521,17 @@ bool T_ParserImpl_::collectGlobalTypes( ) noexcept
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add new entries
|
||||||
T_Decl_ const* const existing( type.get( id ) );
|
T_Decl_ const* const existing( type.get( id ) );
|
||||||
if ( !existing ) {
|
if ( !existing ) {
|
||||||
type.add( id , T_Decl_{ dt , location } );
|
type.add( id , T_Decl_{ dt , location } );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure it matches previous declarations
|
||||||
if ( existing->type == dt ) {
|
if ( existing->type == dt ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( existing->type == E_DataType::BUILTIN ) {
|
if ( existing->type == E_DataType::BUILTIN ) {
|
||||||
esb << "trying to redefine built-in variable " << id;
|
esb << "trying to redefine built-in variable " << id;
|
||||||
} else {
|
} else {
|
||||||
|
@ -528,6 +546,7 @@ bool T_ParserImpl_::collectGlobalTypes( ) noexcept
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy type table to the output
|
||||||
for ( auto const& k : type.keys( ) ) {
|
for ( auto const& k : type.keys( ) ) {
|
||||||
output->types.add( k , type.get( k )->type );
|
output->types.add( k , type.get( k )->type );
|
||||||
}
|
}
|
||||||
|
@ -613,64 +632,45 @@ bool T_ParserImpl_::checkArgumentTypes( ) noexcept
|
||||||
assert( call->arguments( ) == calledFn.arguments( ) );
|
assert( call->arguments( ) == calledFn.arguments( ) );
|
||||||
if ( argsResolved[ calledIdx ] ) {
|
if ( argsResolved[ calledIdx ] ) {
|
||||||
TRACE( " argument types already resolved, checking" );
|
TRACE( " argument types already resolved, checking" );
|
||||||
for ( auto a = 0u ; a < call->arguments( ) ; a ++ ) {
|
|
||||||
auto& arg( call->argument( a ) );
|
|
||||||
E_DataType ndt{ E_DataType::UNKNOWN };
|
|
||||||
if ( arg.type( ) == A_Node::EXPR_ID ) {
|
|
||||||
T_String const& id( dynamic_cast< T_IdentifierExprNode& >( arg ).id( ) );
|
|
||||||
if ( f.hasLocal( id ) ) {
|
|
||||||
ndt = f.getLocalType( id );
|
|
||||||
} else {
|
|
||||||
auto const* const ptr( output->types.get( id ) );
|
|
||||||
if ( ptr ) {
|
|
||||||
ndt = *ptr;
|
|
||||||
} else {
|
|
||||||
errors.addNew( "unknown identifier" ,
|
|
||||||
arg.location( ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ndt = E_DataType::VARIABLE;
|
|
||||||
}
|
|
||||||
TRACE( " [" << a << "] " << ndt );
|
|
||||||
if ( ndt != E_DataType::UNKNOWN && calledFn.getLocalType( a ) != ndt ) {
|
|
||||||
esb << "argument " << ( a + 1 ) << " of function '"
|
|
||||||
<< called << "' should be a "
|
|
||||||
<< calledFn.getLocalType( a )
|
|
||||||
<< " but a " << ndt << " is being passed";
|
|
||||||
errors.addNew( std::move( esb ) , arg.location( ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
changed = true;
|
|
||||||
} else {
|
} else {
|
||||||
TRACE( " resolving arguments" );
|
TRACE( " resolving arguments" );
|
||||||
bool ok = true;
|
|
||||||
for ( auto a = 0u ; a < call->arguments( ) ; a ++ ) {
|
|
||||||
auto& arg( call->argument( a ) );
|
|
||||||
E_DataType ndt{ E_DataType::UNKNOWN };
|
|
||||||
if ( arg.type( ) == A_Node::EXPR_ID ) {
|
|
||||||
T_String const& id( dynamic_cast< T_IdentifierExprNode& >( arg ).id( ) );
|
|
||||||
if ( f.hasLocal( id ) ) {
|
|
||||||
ndt = f.getLocalType( id );
|
|
||||||
} else {
|
|
||||||
auto const* const ptr( output->types.get( id ) );
|
|
||||||
if ( ptr ) {
|
|
||||||
ndt = *ptr;
|
|
||||||
} else {
|
|
||||||
errors.addNew( "unknown identifier" ,
|
|
||||||
arg.location( ) );
|
|
||||||
ok = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ndt = E_DataType::VARIABLE;
|
|
||||||
}
|
|
||||||
TRACE( " [" << a << "] " << ndt );
|
|
||||||
calledFn.setLocalType( a , ndt );
|
|
||||||
}
|
|
||||||
argsResolved[ calledIdx ] = ok;
|
|
||||||
changed = changed || ok;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ok = true;
|
||||||
|
for ( auto a = 0u ; a < call->arguments( ) ; a ++ ) {
|
||||||
|
auto& arg( call->argument( a ) );
|
||||||
|
E_DataType ndt{ E_DataType::UNKNOWN };
|
||||||
|
if ( arg.type( ) == A_Node::EXPR_ID ) {
|
||||||
|
auto const& idn( dynamic_cast< T_IdentifierExprNode& >( arg ) );
|
||||||
|
T_String const& id( idn.id( ) );
|
||||||
|
ndt = getTypeOf( id , &f );
|
||||||
|
if ( ndt == E_DataType::UNKNOWN ) {
|
||||||
|
errors.addNew( "unknown identifier" ,
|
||||||
|
arg.location( ) );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ndt = E_DataType::VARIABLE;
|
||||||
|
}
|
||||||
|
TRACE( " [" << a << "] " << ndt );
|
||||||
|
|
||||||
|
// Arguments not resolved -> try setting the argument's type
|
||||||
|
if ( !argsResolved[ calledIdx ] ) {
|
||||||
|
ok = ( ndt != E_DataType::UNKNOWN );
|
||||||
|
calledFn.setLocalType( a , ndt );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Arguments resolved -> error if types don't match
|
||||||
|
if ( ndt != E_DataType::UNKNOWN && calledFn.getLocalType( a ) != ndt ) {
|
||||||
|
esb << "argument " << ( a + 1 ) << " of function '"
|
||||||
|
<< called << "' should be a "
|
||||||
|
<< calledFn.getLocalType( a )
|
||||||
|
<< " but a " << ndt << " is being passed";
|
||||||
|
errors.addNew( std::move( esb ) , arg.location( ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
argsResolved[ calledIdx ] = ok;
|
||||||
|
changed = changed || ok;
|
||||||
callInstuctions.get( i , c ) = nullptr;
|
callInstuctions.get( i , c ) = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -752,6 +752,24 @@ bool T_ParserImpl_::checkIdentifierExpressions( ) noexcept
|
||||||
|
|
||||||
/*------------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
E_DataType T_ParserImpl_::getTypeOf(
|
||||||
|
T_String const& name ,
|
||||||
|
A_FuncNode const* context ) const noexcept
|
||||||
|
{
|
||||||
|
if ( context && context->hasLocal( name ) ) {
|
||||||
|
return context->getLocalType( name );
|
||||||
|
} else {
|
||||||
|
auto const* const ptr( output->types.get( name ) );
|
||||||
|
if ( ptr ) {
|
||||||
|
return *ptr;
|
||||||
|
} else {
|
||||||
|
return E_DataType::UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
bool T_ParserImpl_::parseTopLevel(
|
bool T_ParserImpl_::parseTopLevel(
|
||||||
T_SRDList const& input ) noexcept
|
T_SRDList const& input ) noexcept
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue