0

I have written a custom logger and wanted to add the name of POUs as the pszComponent for easier debugging.
I wrote a custom FB_init which accepts as input the name of the POU as a string and encountered puzzling behavior (to me at least).

Could someone explain to me why the following compiles

VAR
  name : STRING := __POUNAME();
  test : FB_logAdd(sCmpName:=name);
END_VAR

but the following

VAR
  test : FB_logAdd(sCmpName:=__POUNAME());
END_VAR

throws the following compiler error?

[ERROR]         Internal error:System.NullReferenceException: Object reference not set to an instance of an object.    at _3S.CoDeSys.LanguageModelManager.CompileContext.NeedsExternalFunctionCall(IOperatorExpression op, ICompiledType type, String& stFunctionName, TypeClass& tcWithType)    at _3S.CoDeSys.Compiler35160.ExpressionTypifier.(_IOperatorExpression )    at _3S.CoDeSys.LanguageModelManager.OperatorExpression.Accept(IExprementVisitor visitor)    at _3S.CoDeSys.Compiler35160.InterfaceCompiler.(_IVariable , _ISignature , ISignature , ISignature , IScope5 , _ICompileContext , IList`1 , IVariable[] , ExpressionTypifier , TypeChecker , ErrorVisitor )    at _3S.CoDeSys.Compiler35160.InterfaceCompiler.(IList`1& , IVariable[] , _IVariable , IScope5 , _ICompileContext , _ISignature , ISignature , ISignature , ExpressionTypifier , TypeChecker , ErrorVisitor )    at _3S.CoDeSys.Compiler35160.InterfaceCompiler.(_IVariable , IScope5 , _ICompileContext , _ISignature , ISignature , ISignature , ExpressionTypifier , TypeChecker , ErrorVisitor )    at _3S.CoDeSys.Compiler35160.InterfaceCompiler.(_IVariable , IScope5 , _ICompileContext , _ISignature , ExpressionTypifier , TypeChecker , ErrorVisitor , ISignature , ISignature )    at _3S.CoDeSys.Compiler35160.InterfaceCompiler.(_IVariable , IScope5 , _ICompileContext , _ISignature )    at _3S.CoDeSys.Compiler35160.InterfaceCompiler.(_ISignature , IScope5 , _ICompileContext )    at _3S.CoDeSys.Compiler35160.Compiler.(_ICompileContext , _IPreCompileContext , _IPreCompileContext , _ICompileContext , Boolean , Boolean , Boolean& , IProgressCallback )    at _3S.CoDeSys.Compiler35160.Compiler.(_ICompileContext , Boolean , Boolean , _IPreCompileContext , _IPreCompileContext , _ICompileContext , Boolean , Boolean& , IProgressCallback )    at _3S.CoDeSys.Compiler35160.Compiler.(Guid , Boolean , Boolean , Boolean , Boolean& , _ICompileContext& , _ICompileContext& , IProgressCallback , Boolean , Boolean , Boolean )

Is it because __POUNAME() behaves like a function block instead of a function like I assumed?
Which is why

VAR
  test : FB_logAdd(pCmpName:=ADR(__POUNAME()));
END_VAR

also works if I change the input to a string pointer?

Edit 1

My initial FB_init looked like this

//FB_Init is always available implicitly and it is used primarily for initialization.
//The return value is not evaluated. For a specific influence, you can also declare the
//methods explicitly and provide additional code there with the standard initialization
//code. You can evaluate the return value.
METHOD FB_Init: BOOL
VAR_INPUT
    bInitRetains: BOOL; // TRUE: the retain variables are initialized (reset warm / reset cold)
    bInCopyCode: BOOL;  // TRUE: the instance will be copied to the copy code afterward (online change)   
    sCmpName : STRING;
END_VAR

THIS^.sCmpName := sCmpName;

Since I wanted to initialize the function block with FB_logAdd(sCmpName:=__POUNAME()) (which still throws the above error)

If I use FB_logAdd(sCmpName:=THIS^.___POUNAME()), it throws the compiler error

C0004:  '__POUNAME' is no component of 'THIS^'

which makes sense since __POUNAME() is an operator and doesn't actually belong to the parent function block (I think)

void
  • 7
  • 3
  • I don't know why it happens. It may even be a bug for all we know. This line seems to be interesting: `...NeedsExternalFunctionCall(...`, is it trying to access the `__POUNAME` of a different POU? Seems really strange. Could you try using `THIS^` (`sCmpName := THIS^.__POUNAME()`)? – Guiorgy Dec 13 '21 at 13:13
  • @Guiorgy I don't quite understand where I'm supposed to use `THIS^ (sCmpName := THIS^.__POUNAME())`, look above for what I tried – void Dec 14 '21 at 16:01
  • The [documentation](https://help.codesys.com/webapp/_cds_operator_pouname;product=codesys;version=3.5.17.0) states that "*At __runtime__, the operator yields the name...*", so you might be right that `__POUNAME` is not evaluated to a string at compile time. The [instance-path](https://help.codesys.com/webapp/_cds_pragma_attribute_instance_path;product=codesys;version=3.5.17.0) attribute is an alternative, but in that case too you would need a local STRING variable to hold the name anyways. – Guiorgy Dec 14 '21 at 17:09
  • @Guiorgy ah ok, but in that case, the reason why `FB_logAdd(pCmpName:=ADR(__POUNAME()))` works is because the pointer exists at compile time even though what it points to doesn't? And then at runtime, that is resolved? – void Dec 14 '21 at 20:44
  • As I said, this behaviour is strange. I can only guess that `__POUNAME` uses some resources available in the local scope at runtime to resolve the pou name. Perhaps when you pass the pointer, the scope is set to the caller, while when you pass by value the scope is the callee and `__POUNAME` must be trying to access some resource of the caller but fails: `...NeedsExternalFunctionCall(...`. But again, this is just speculation. Your best bet would be to contact [CODESYS support](https://www.codesys.com/support-training/codesys-support.html) dirrectly, but if I remember correctly, it's not free – Guiorgy Dec 15 '21 at 09:14

0 Answers0