How does symbol solving work for a general purpose language?

Programs of a typed language (where supplying declarations such as members with type expressions allow for compile-time verifications) have to be verified and have references resolved before tasks such as compilation (be it bytecode generation or some other target).

I’ve several times implemented node verification in a phase-based distribution for my dialect, but it always were mostly the same. Every node (like a top declaration) is visited with a phase parameter (preferably inside a context object). Nodes are, eventually, partially solved according to the phase parameter.

For example, here’s a VB dialect being solved (simplified). Given a sequence of statements:

phase1: For every class C, define into the lexical frame the name C as a new class symbol if C is not defined. Throw a verify error if the name C is already defined. For every member declaration M, define into the lexical frame the name M as a new variable slot symbol (with the associated type currently empty) if M is not defiined. Throw a verify error if the name M is already defined.

phase2: For every member declaration, resolve the corresponding type expression if any and if resolved, update the member associated type. For every class with a Inherits clause, resolve the Inherits type expression. For every class C with substatement sequence cs, apply phase1 to every substatement and then phase2.

Class SomeType
    Inherits Object
    ' Member associated type is not resolved until phase 2
    Public Embedded As SomeType?
End Class

That’s kind of how my symbol solver works. I’m going to rewrite my last symbol solver to work for a VB dialect (before it was syntatically ECMAScript).

I’d like to know if I could improve my terminology. I appreciate any feedback.

1 Like