Compiler - Progress on bytecode generator
+ added a technical node for call arguments
This commit is contained in:
parent
f97bb9b596
commit
87b46284ab
5 changed files with 403 additions and 11 deletions
21
control.hh
21
control.hh
|
@ -10,9 +10,30 @@ enum E_OpType
|
|||
{
|
||||
OP_END ,
|
||||
//
|
||||
OP_CALL ,
|
||||
OP_RET ,
|
||||
OP_COND_JUMP ,
|
||||
//
|
||||
OP_RES_STACK ,
|
||||
OP_PUSH ,
|
||||
OP_POP ,
|
||||
//
|
||||
OP_LOAD ,
|
||||
OP_SLOAD ,
|
||||
//
|
||||
OP_FP_LOAD ,
|
||||
OP_FP_STORE ,
|
||||
OP_FP_SLOAD ,
|
||||
OP_FP_SSTORE ,
|
||||
OP_FP_SSTORE_INT ,
|
||||
//
|
||||
OP_FP_CMP ,
|
||||
OP_FP_ADD ,
|
||||
OP_FP_SUB ,
|
||||
OP_FP_MUL ,
|
||||
OP_FP_DIV ,
|
||||
OP_FP_NEG ,
|
||||
OP_FP_INV ,
|
||||
};
|
||||
|
||||
struct T_Op
|
||||
|
|
7
opast.cc
7
opast.cc
|
@ -124,6 +124,13 @@ A_Node* opast::ASTVisitorBrowser(
|
|||
}
|
||||
break;
|
||||
}
|
||||
case A_Node::TN_ARG:
|
||||
{
|
||||
if ( child == 0 ) {
|
||||
return &( (T_CallInstrNode::T_Argument&) node ).expression( );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Clear instruction
|
||||
case A_Node::OP_CLEAR:
|
||||
|
|
29
opast.hh
29
opast.hh
|
@ -66,6 +66,7 @@ class A_Node
|
|||
TN_CONDITION , // Expression for a conditional instruction
|
||||
TN_CASE , // Valued case for a conditional instruction
|
||||
TN_DEFAULT , // Default case for a conditional instruction
|
||||
TN_ARG , // Call argument
|
||||
};
|
||||
|
||||
private:
|
||||
|
@ -249,6 +250,8 @@ class A_FuncNode : public A_Node
|
|||
T_String const& name ,
|
||||
T_SRDLocation const& location ) noexcept;
|
||||
|
||||
uint32_t locals( ) const noexcept
|
||||
{ return locals_.size( ); }
|
||||
bool hasLocal( T_String const& id ) const noexcept
|
||||
{ return locals_.contains( id ); }
|
||||
|
||||
|
@ -373,10 +376,29 @@ class T_FuncNode : public A_FuncNode
|
|||
// Function call
|
||||
class T_CallInstrNode : public A_InstructionNode
|
||||
{
|
||||
public:
|
||||
class T_Argument : public A_Node
|
||||
{
|
||||
private:
|
||||
P_ExpressionNode expr_;
|
||||
|
||||
public:
|
||||
T_Argument( T_CallInstrNode& parent ,
|
||||
P_ExpressionNode expr ) noexcept
|
||||
: A_Node( TN_ARG , &parent ) ,
|
||||
expr_( std::move( expr ) )
|
||||
{ }
|
||||
|
||||
A_ExpressionNode& expression( ) const noexcept
|
||||
{ return *expr_; }
|
||||
bool isIdentifier( ) const noexcept
|
||||
{ return expr_->type( ) == EXPR_ID; }
|
||||
};
|
||||
|
||||
private:
|
||||
T_String id_;
|
||||
T_SRDLocation idLocation_;
|
||||
T_AutoArray< P_ExpressionNode , 8 > arguments_;
|
||||
T_AutoArray< T_OwnPtr< T_Argument > , 8 > arguments_;
|
||||
|
||||
public:
|
||||
T_CallInstrNode( T_InstrListNode& parent ,
|
||||
|
@ -389,7 +411,8 @@ class T_CallInstrNode : public A_InstructionNode
|
|||
void addArgument( P_ExpressionNode expr ) noexcept
|
||||
{
|
||||
if ( expr ) {
|
||||
arguments_.add( std::move( expr ) );
|
||||
arguments_.add( NewOwned< T_Argument >(
|
||||
*this , std::move( expr ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -400,7 +423,7 @@ class T_CallInstrNode : public A_InstructionNode
|
|||
|
||||
uint32_t arguments( ) const noexcept
|
||||
{ return arguments_.size( ); }
|
||||
A_ExpressionNode& argument( const uint32_t index ) const noexcept
|
||||
T_Argument& argument( const uint32_t index ) const noexcept
|
||||
{ return *arguments_[ index ]; }
|
||||
};
|
||||
|
||||
|
|
355
opcomp.cc
355
opcomp.cc
|
@ -12,8 +12,13 @@ namespace {
|
|||
|
||||
struct T_CompilerImpl_
|
||||
{
|
||||
P_OpProgram compile(
|
||||
T_ParserOutput const& input ) noexcept;
|
||||
|
||||
private:
|
||||
T_Visitor< A_Node > astVisitor{ ASTVisitorBrowser };
|
||||
T_Set< uint32_t > constants{ UseTag< IndexBacked< > >( ) };
|
||||
T_KeyValueTable< T_String , uint32_t > locations;
|
||||
|
||||
T_ParserOutput* input;
|
||||
P_OpProgram output;
|
||||
|
@ -22,16 +27,29 @@ struct T_CompilerImpl_
|
|||
fiPipelines , fiPrograms ,
|
||||
fiSamplers , fiTextures;
|
||||
|
||||
P_OpProgram compile(
|
||||
T_ParserOutput const& input ) noexcept;
|
||||
uint32_t sdMain , sdFPU;
|
||||
T_AutoArray< uint32_t , 32 > condJumps;
|
||||
|
||||
private:
|
||||
void gatherConstants( ) noexcept;
|
||||
void countAssets( ) noexcept;
|
||||
|
||||
bool compileNode( uint32_t funcIndex ,
|
||||
A_Node& node ,
|
||||
bool exit ) noexcept;
|
||||
void processFunction(
|
||||
bool exit ,
|
||||
uint32_t args ,
|
||||
uint32_t lvars ,
|
||||
T_SRDLocation const& location ) noexcept;
|
||||
bool processIdentifier(
|
||||
uint32_t funcIndex ,
|
||||
T_IdentifierExprNode const& node ) noexcept;
|
||||
|
||||
void addInstruction(
|
||||
E_OpType op ,
|
||||
T_SRDLocation const& location ,
|
||||
uint32_t arg0 = 0 ,
|
||||
uint32_t arg1 = 0 ) noexcept;
|
||||
};
|
||||
|
||||
|
||||
|
@ -56,6 +74,9 @@ P_OpProgram T_CompilerImpl_::compile(
|
|||
#endif
|
||||
|
||||
// Compile each function
|
||||
#ifdef INVASIVE_TRACES
|
||||
uint32_t nInstr = 0;
|
||||
#endif
|
||||
uint32_t cfi;
|
||||
for ( cfi = 0u ; cfi < input->root.nFunctions( ) ; cfi ++ ) {
|
||||
output->ops.next( );
|
||||
|
@ -64,11 +85,19 @@ P_OpProgram T_CompilerImpl_::compile(
|
|||
printf( "compiling function %s\n" ,
|
||||
func.name( ).toOSString( ).data( ) );
|
||||
#endif
|
||||
sdMain = sdFPU = 0;
|
||||
astVisitor.visit( func ,
|
||||
[=]( A_Node& node , const bool exit ) -> bool {
|
||||
return compileNode( cfi , node , exit );
|
||||
} );
|
||||
#ifdef INVASIVE_TRACES
|
||||
printf( "\t%d instructions generated\n" , output->ops.sizeOf( cfi ) );
|
||||
nInstr += output->ops.sizeOf( cfi );
|
||||
#endif
|
||||
}
|
||||
#ifdef INVASIVE_TRACES
|
||||
printf( "total %d instructions\n" , nInstr );
|
||||
#endif
|
||||
|
||||
return std::move( output );
|
||||
}
|
||||
|
@ -80,9 +109,7 @@ void T_CompilerImpl_::gatherConstants( ) noexcept
|
|||
if ( exit && node.type( ) == A_Node::EXPR_CONST ) {
|
||||
T_OpValue value;
|
||||
value.f = dynamic_cast< T_ConstantExprNode& >( node ).floatValue( );
|
||||
if ( value.f != 0 && value.f != 1 ) {
|
||||
constants.add( value.u );
|
||||
}
|
||||
constants.add( value.u );
|
||||
}
|
||||
return true;
|
||||
} );
|
||||
|
@ -103,26 +130,38 @@ void T_CompilerImpl_::gatherConstants( ) noexcept
|
|||
|
||||
void T_CompilerImpl_::countAssets( ) noexcept
|
||||
{
|
||||
locations.clear( );
|
||||
locations.add( T_String::Pooled( "time" ) , 0u );
|
||||
locations.add( T_String::Pooled( "width" ) , 1u );
|
||||
locations.add( T_String::Pooled( "height" ) , 2u );
|
||||
|
||||
auto const nt{ input->types.size( ) };
|
||||
for ( auto i = 0u ; i < nt ; i ++ ) {
|
||||
const auto t{ input->types.values( )[ i ] };
|
||||
auto const& n{ input->types.keys( )[ i ] };
|
||||
switch ( t ) {
|
||||
case E_DataType::FRAMEBUFFER:
|
||||
locations.add( n , output->nFramebuffers );
|
||||
output->nFramebuffers ++;
|
||||
break;
|
||||
case E_DataType::PIPELINE:
|
||||
locations.add( n , output->nPipelines );
|
||||
output->nPipelines ++;
|
||||
break;
|
||||
case E_DataType::PROGRAM:
|
||||
locations.add( n , output->nPrograms );
|
||||
output->nPrograms ++;
|
||||
break;
|
||||
case E_DataType::SAMPLER:
|
||||
locations.add( n , output->nSamplers );
|
||||
output->nSamplers ++;
|
||||
break;
|
||||
case E_DataType::TEXTURE:
|
||||
locations.add( n , output->nTextures );
|
||||
output->nTextures ++;
|
||||
break;
|
||||
case E_DataType::VARIABLE:
|
||||
locations.add( n , output->nVariables + 3 );
|
||||
output->nVariables ++;
|
||||
break;
|
||||
|
||||
|
@ -145,6 +184,29 @@ void T_CompilerImpl_::countAssets( ) noexcept
|
|||
fiSamplers = fiPrograms + output->nPrograms;
|
||||
fiTextures = fiSamplers + output->nSamplers;
|
||||
|
||||
for ( auto i = 0u ; i < nt ; i ++ ) {
|
||||
const auto li{ locations.indexOf( input->types.keys( )[ i ] ) };
|
||||
if ( li == T_HashIndex::INVALID_INDEX ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto t{ input->types.values( )[ i ] };
|
||||
auto& pos{ locations[ li ] };
|
||||
switch ( t ) {
|
||||
case E_DataType::FRAMEBUFFER: pos += fiFramebuffers; break;
|
||||
case E_DataType::PIPELINE: pos += fiPipelines; break;
|
||||
case E_DataType::PROGRAM: pos += fiPrograms; break;
|
||||
case E_DataType::SAMPLER: pos += fiSamplers; break;
|
||||
case E_DataType::TEXTURE: pos += fiTextures; break;
|
||||
|
||||
case E_DataType::VARIABLE:
|
||||
case E_DataType::INPUT:
|
||||
case E_DataType::BUILTIN:
|
||||
case E_DataType::UNKNOWN:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef INVASIVE_TRACES
|
||||
printf( "assets\n\t%d framebuffers\n\t%d pipelines\n"
|
||||
"\t%d programs\n\t%d samplers\n\t%d textures\n"
|
||||
|
@ -165,6 +227,26 @@ void T_CompilerImpl_::countAssets( ) noexcept
|
|||
fiPipelines - 1 , fiPipelines , fiPrograms - 1 , fiPrograms ,
|
||||
fiSamplers - 1 , fiSamplers , fiTextures - 1 , fiTextures ,
|
||||
fiTextures + output->nTextures - 1 );
|
||||
|
||||
T_Array< uint32_t > indices( locations.size( ) );
|
||||
indices.ensureCapacity( locations.size( ) );
|
||||
for ( auto i = 0u ; i < locations.size( ) ; i ++ ) {
|
||||
indices.add( i );
|
||||
}
|
||||
indices.sort( [this]( uint32_t a , uint32_t b ) {
|
||||
return T_Comparator< uint32_t >::compare(
|
||||
locations.values( )[ a ] ,
|
||||
locations.values( )[ b ] );
|
||||
} );
|
||||
T_StringBuilder lmap;
|
||||
lmap << "location map (constants not included)\n";
|
||||
for ( auto idx : indices ) {
|
||||
lmap << '\t' << locations.values( )[ idx ]
|
||||
<< '\t' << locations.keys( )[ idx ]
|
||||
<< '\n';
|
||||
}
|
||||
lmap << '\0';
|
||||
printf( "%s" , lmap.data( ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -173,7 +255,266 @@ bool T_CompilerImpl_::compileNode(
|
|||
A_Node& node ,
|
||||
const bool exit ) noexcept
|
||||
{
|
||||
return false;
|
||||
switch ( node.type( ) ) {
|
||||
|
||||
case A_Node::ROOT:
|
||||
fprintf( stderr , "Internal error: root node found during compilation\n" );
|
||||
std::abort( );
|
||||
break;
|
||||
|
||||
case A_Node::DECL_FN:
|
||||
{
|
||||
T_FuncNode& fn( (T_FuncNode&) node );
|
||||
const auto args( fn.arguments( ) );
|
||||
processFunction( exit , args , fn.locals( ) - args , node.location( ) );
|
||||
break;
|
||||
}
|
||||
|
||||
case A_Node::DECL_INIT:
|
||||
case A_Node::DECL_FRAME:
|
||||
{
|
||||
A_FuncNode& fn( (A_FuncNode&) node );
|
||||
processFunction( exit , 0 , fn.locals( ) , node.location( ) );
|
||||
break;
|
||||
}
|
||||
|
||||
case A_Node::OP_CALL:
|
||||
if ( exit ) {
|
||||
auto& call( (T_CallInstrNode&) node );
|
||||
const auto fi( input->root.functionIndex( call.id( ) ) );
|
||||
assert( fi >= 0 );
|
||||
auto& callee( input->root.function( fi ) );
|
||||
assert( callee.type( ) == A_Node::DECL_FN );
|
||||
auto& fcallee( (T_FuncNode&) callee );
|
||||
const auto args( fcallee.arguments( ) );
|
||||
assert( sdMain > args );
|
||||
addInstruction( OP_CALL , node.location( ) , fi );
|
||||
sdMain -= args;
|
||||
}
|
||||
break;
|
||||
case A_Node::TN_ARG:
|
||||
{
|
||||
auto& n( (T_CallInstrNode::T_Argument&)node );
|
||||
if ( n.isIdentifier( ) && !exit ) {
|
||||
const bool main{ processIdentifier( funcIndex ,
|
||||
(T_IdentifierExprNode&) n.expression( ) ) };
|
||||
if ( !main ) {
|
||||
addInstruction( OP_PUSH , node.location( ) );
|
||||
addInstruction( OP_FP_SSTORE , node.location( ) , 0 );
|
||||
sdMain ++;
|
||||
sdFPU --;
|
||||
}
|
||||
return false;
|
||||
} else if ( exit && !n.isIdentifier( ) ) {
|
||||
addInstruction( OP_PUSH , node.location( ) );
|
||||
addInstruction( OP_FP_SSTORE , node.location( ) , 0 );
|
||||
sdMain ++;
|
||||
sdFPU --;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case A_Node::OP_SET:
|
||||
if ( exit ) {
|
||||
assert( sdFPU > 0 );
|
||||
auto& id( ((T_SetInstrNode&)node).id( ) );
|
||||
auto& func{ input->root.function( funcIndex ) };
|
||||
if ( func.hasLocal( id ) ) {
|
||||
const auto pos( func.getLocalIndex( id ) + 1 );
|
||||
addInstruction( OP_FP_SSTORE , node.location( ) ,
|
||||
sdMain - pos - 1 );
|
||||
} else {
|
||||
addInstruction( OP_FP_STORE , node.location( ) ,
|
||||
*locations.get( ((T_SetInstrNode&)node).id( ) ) );
|
||||
}
|
||||
sdFPU --;
|
||||
}
|
||||
break;
|
||||
|
||||
case A_Node::OP_COND:
|
||||
if ( exit ) {
|
||||
assert( sdMain > 0 );
|
||||
addInstruction( OP_POP , node.location( ) , 0 );
|
||||
sdMain --;
|
||||
}
|
||||
break;
|
||||
|
||||
case A_Node::TN_CONDITION:
|
||||
if ( exit ) {
|
||||
addInstruction( OP_PUSH , node.location( ) );
|
||||
addInstruction( OP_FP_SSTORE_INT , node.location( ) , 0 );
|
||||
sdFPU --;
|
||||
sdMain ++;
|
||||
}
|
||||
break;
|
||||
|
||||
case A_Node::TN_CASE:
|
||||
if ( exit ) {
|
||||
const auto cpos( output->ops.sizeOf( funcIndex ) );
|
||||
const auto diff( cpos - condJumps.last( ) );
|
||||
output->ops.get( funcIndex , condJumps.last( ) ).arg1 = diff - 1;
|
||||
condJumps.removeLast( );
|
||||
#ifdef INVASIVE_TRACES
|
||||
printf( "\tCOND JUMP UPDATED: %d\n" , diff - 1 );
|
||||
#endif
|
||||
} else {
|
||||
auto& c( (T_CondInstrNode::T_ValuedCase&) node );
|
||||
condJumps.add( output->ops.sizeOf( funcIndex ) );
|
||||
addInstruction( OP_COND_JUMP , node.location( ) ,
|
||||
c.value( ) , 0 );
|
||||
}
|
||||
break;
|
||||
|
||||
case A_Node::EXPR_CMP_EQ: case A_Node::EXPR_CMP_NE:
|
||||
case A_Node::EXPR_CMP_GT: case A_Node::EXPR_CMP_GE:
|
||||
case A_Node::EXPR_CMP_LT: case A_Node::EXPR_CMP_LE:
|
||||
if ( exit ) {
|
||||
const uint32_t op( dynamic_cast< T_BinaryOperatorNode& >( node ).op( )
|
||||
- T_BinaryOperatorNode::CMP_EQ );
|
||||
addInstruction( OP_FP_CMP , node.location( ) , op );
|
||||
}
|
||||
break;
|
||||
|
||||
case A_Node::EXPR_ADD:
|
||||
if ( exit ) {
|
||||
assert( sdFPU > 2 );
|
||||
addInstruction( OP_FP_ADD , node.location( ) );
|
||||
sdFPU --;
|
||||
}
|
||||
break;
|
||||
case A_Node::EXPR_SUB:
|
||||
if ( exit ) {
|
||||
assert( sdFPU > 2 );
|
||||
addInstruction( OP_FP_SUB , node.location( ) );
|
||||
sdFPU --;
|
||||
}
|
||||
break;
|
||||
case A_Node::EXPR_MUL:
|
||||
if ( exit ) {
|
||||
assert( sdFPU > 2 );
|
||||
addInstruction( OP_FP_MUL , node.location( ) );
|
||||
sdFPU --;
|
||||
}
|
||||
break;
|
||||
case A_Node::EXPR_DIV:
|
||||
if ( exit ) {
|
||||
assert( sdFPU > 2 );
|
||||
addInstruction( OP_FP_DIV , node.location( ) );
|
||||
sdFPU --;
|
||||
}
|
||||
break;
|
||||
|
||||
case A_Node::EXPR_CONST:
|
||||
if ( !exit ) {
|
||||
T_OpValue value;
|
||||
value.f = dynamic_cast< T_ConstantExprNode& >( node ).floatValue( );
|
||||
addInstruction( OP_FP_LOAD , node.location( ) ,
|
||||
constants.indexOf( value.u ) + 3 );
|
||||
sdFPU ++;
|
||||
}
|
||||
break;
|
||||
|
||||
case A_Node::EXPR_ID:
|
||||
if ( !exit ) {
|
||||
processIdentifier( funcIndex ,
|
||||
dynamic_cast< T_IdentifierExprNode& >( node ) );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void T_CompilerImpl_::processFunction(
|
||||
const bool exit ,
|
||||
const uint32_t args ,
|
||||
const uint32_t lvars ,
|
||||
T_SRDLocation const& location ) noexcept
|
||||
{
|
||||
if ( exit ) {
|
||||
assert( sdMain == args + lvars + 1 );
|
||||
if ( lvars ) {
|
||||
addInstruction( OP_POP , location , lvars - 1 );
|
||||
sdMain -= lvars;
|
||||
}
|
||||
sdMain -= 1 + args;
|
||||
addInstruction( OP_RET , location , args );
|
||||
assert( sdMain == 0 );
|
||||
} else {
|
||||
if ( lvars ) {
|
||||
addInstruction( OP_RES_STACK , location , lvars - 1 );
|
||||
sdMain += lvars;
|
||||
}
|
||||
sdMain += 1 + args;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if the identifier caused a push to the main stack, false
|
||||
// if it pushed to the FPU stack.
|
||||
bool T_CompilerImpl_::processIdentifier(
|
||||
const uint32_t funcIndex ,
|
||||
T_IdentifierExprNode const& node ) noexcept
|
||||
{
|
||||
auto& func{ input->root.function( funcIndex ) };
|
||||
if ( func.hasLocal( node.id( ) ) ) {
|
||||
const E_DataType dt{ func.getLocalType( node.id( ) ) };
|
||||
assert( dt != E_DataType::UNKNOWN );
|
||||
|
||||
uint32_t stackPos;
|
||||
if ( func.isArgument( node.id( ) ) ) {
|
||||
auto const& fn( (T_FuncNode&) func );
|
||||
const auto nArgs( fn.arguments( ) );
|
||||
stackPos = nArgs - 1 - func.getLocalIndex( node.id( ) );
|
||||
} else {
|
||||
stackPos = func.getLocalIndex( node.id( ) ) + 1;
|
||||
}
|
||||
assert( stackPos < sdMain );
|
||||
|
||||
const auto p( sdMain - ( stackPos + 1 ) );
|
||||
if ( dt == E_DataType::VARIABLE ) {
|
||||
addInstruction( OP_FP_SLOAD , node.location( ) , p );
|
||||
sdFPU ++;
|
||||
return false;
|
||||
}
|
||||
|
||||
addInstruction( OP_SLOAD , node.location( ) , p );
|
||||
addInstruction( OP_PUSH , node.location( ) );
|
||||
sdMain ++;
|
||||
return true;
|
||||
}
|
||||
|
||||
assert( input->types.contains( node.id( ) ) );
|
||||
const E_DataType dt{ *( input->types.get( node.id( ) ) ) };
|
||||
assert( dt != E_DataType::UNKNOWN );
|
||||
assert( locations.contains( node.id( ) ) );
|
||||
if ( dt == E_DataType::VARIABLE || dt == E_DataType::BUILTIN ) {
|
||||
addInstruction( OP_FP_LOAD , node.location( ) ,
|
||||
*locations.get( node.id( ) ) );
|
||||
sdFPU ++;
|
||||
return false;
|
||||
}
|
||||
|
||||
addInstruction( OP_LOAD , node.location( ) ,
|
||||
*locations.get( node.id( ) ) );
|
||||
addInstruction( OP_PUSH , node.location( ) );
|
||||
sdMain ++;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void T_CompilerImpl_::addInstruction(
|
||||
const E_OpType op ,
|
||||
T_SRDLocation const& location ,
|
||||
const uint32_t arg0 ,
|
||||
const uint32_t arg1 ) noexcept
|
||||
{
|
||||
#ifdef INVASIVE_TRACES
|
||||
T_StringBuilder tracer;
|
||||
tracer << "\t+I( " << int( op ) << " ; " << arg0 << " ; "
|
||||
<< arg1 << " ) @ " << location << '\n' << '\0';
|
||||
printf( "%s" , tracer.data( ) );
|
||||
#endif
|
||||
output->ops.addNew( op , location , arg0 , arg1 );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -648,7 +648,7 @@ bool T_ParserImpl_::checkArgumentTypes( ) noexcept
|
|||
|
||||
bool ok = true;
|
||||
for ( auto a = 0u ; a < call->arguments( ) ; a ++ ) {
|
||||
auto& arg( call->argument( a ) );
|
||||
auto& arg( call->argument( a ).expression( ) );
|
||||
E_DataType ndt{ E_DataType::UNKNOWN };
|
||||
if ( arg.type( ) == A_Node::EXPR_ID ) {
|
||||
auto const& idn( dynamic_cast< T_IdentifierExprNode& >( arg ) );
|
||||
|
|
Loading…
Reference in a new issue