Language Design and Semantics-- Language Semantics to Compiler Design
In a previous blog entry, language design can impact the design of the compiler, especially the semantic checks. A one pass compiler seems to require a more restrictive language akin to Pascal, with strict declaration before use semantics. That simplifies the compiler design and compiler writers task of creating an efficient (efficient in being a one pass design) compiler.
One possibility from Pascal (actually stemming from a limitation of Pascal) is a forward declaration -- adding a feature into the language (instead constraining a feature). As the compiler for Mynx uses sentential or bounded context of a sentence parsing, it is simply adding a keyword into the language, and the prefix and suffix for a sentence. Something like:
The disadvantage is adding another sentence and keyword into the language, and for the convenience of the compiler writer and the compiler design.
Alternatively, Mynx already has the feature of method equivalents, so once could define a dummy method as a forward declaration, as:
This has the comparative advantage that no new language feature is necessary, and uses a feature already in the language (and not designed for that purpose, but that illustrates a level of adaptability). The real disadvantage is a Mynx class will have many dummy methods that are confusing and difficult to comprehend, and couples the compiler design to an expected language feature that is not part of the language. There is no explicit syntax for the semantic feature, not like obviating a method which has syntax to explicitly remove a method from a class.
Type annotation is the first part of the last phase of semantic checks of type checks. After uniqueness, and existence semantic checks, type checking verifies that if the elements of a class or program are unique, and exist (are declared and initialized), type checking verifies the elements can be connected in expressions and statements -- are type compatible. Before checking type compatibility, the elements must have the type information annotated.
Ideally type annotation is done on the fly (OTF...sorta like WTF?!) in a one pass compiler. In terms of read and write:
Within the class or program scope, all methods and attributes are visible within the context of the unit -- hence there is no declaration before use, so first pass writes the type information into the symbol table, the second pass reads the information from the symbol table.
A forward declaration is a stub for the real declaration later on at some point in the class or program. It is a low-fat declaration that writes type into the symbol table.
As previously stated, the added complexity of another syntax construct, and a new lexeme or keyword. A further complication is that after a forward method is parsed, and entered into the symbol table, a post-check requires storing all forward method declarations, and verifying that an actual method was declared exactly but later on in the class.
Another semantic twist is that a forward semantic declaration would require a uniqueness (not declared before), and that an actual method declaration does not proceed the forward method declaration (not declared exactly). Instead of simplifying semantics at the cost and trade-off of added lexical and syntactic elements and processing, more semantic complexity is added in the process.
The result in the compiler design is zero sum (to borrow a term from game theory), so in simplifying of the semantics the complexity has increased in all three phases: lexical, syntax, and semantic.
The simpler approach (and simplicity is better than complexity without any real benefit) is to implicitly require declaration before use, and have the compiler flag a semantic error if an expected attribute or method is not in the symbol table to annotate the type. Of course, this approach is under the requirement of a one pass compiler, for a two pass compiler it would be superfluous.
The real question and the subsequent issues that follow is one pass or two pass, which are driven by the design of the Mynx programming language. In a strange way, its almost a vicious circle with feedback from the design of the compiler design by the compiler writer impacts the design of the language and the programming language designer. The trade-off is that language design complexity is inversely related to the compiler design complexity.
In this case, I am doing both so it is not separate people, but the design issues even in the same head of one person are paradoxical and counter-intuitive. The eventual goal is to find a point of equilibrium between the language design and the compiler design.
As a philosophy professor once might have said, "A long contemplative meditation upon the problem is necessitated."
Moving Forward -- with Forward Method Syntax
One possibility from Pascal (actually stemming from a limitation of Pascal) is a forward declaration -- adding a feature into the language (instead constraining a feature). As the compiler for Mynx uses sentential or bounded context of a sentence parsing, it is simply adding a keyword into the language, and the prefix and suffix for a sentence. Something like:
method blah is forward;
The disadvantage is adding another sentence and keyword into the language, and for the convenience of the compiler writer and the compiler design.
Alternatively, Mynx already has the feature of method equivalents, so once could define a dummy method as a forward declaration, as:
method blah(Void) is to null; //dummy method takes a Void parameter
This has the comparative advantage that no new language feature is necessary, and uses a feature already in the language (and not designed for that purpose, but that illustrates a level of adaptability). The real disadvantage is a Mynx class will have many dummy methods that are confusing and difficult to comprehend, and couples the compiler design to an expected language feature that is not part of the language. There is no explicit syntax for the semantic feature, not like obviating a method which has syntax to explicitly remove a method from a class.
Type Annotation
Type annotation is the first part of the last phase of semantic checks of type checks. After uniqueness, and existence semantic checks, type checking verifies that if the elements of a class or program are unique, and exist (are declared and initialized), type checking verifies the elements can be connected in expressions and statements -- are type compatible. Before checking type compatibility, the elements must have the type information annotated.
Ideally type annotation is done on the fly (OTF...sorta like WTF?!) in a one pass compiler. In terms of read and write:
- declaration of attribute or variable - write type into symbol table.
- expression of attribute or variable - read type from symbol table.
Within the class or program scope, all methods and attributes are visible within the context of the unit -- hence there is no declaration before use, so first pass writes the type information into the symbol table, the second pass reads the information from the symbol table.
Type Annotation Forward
A forward declaration is a stub for the real declaration later on at some point in the class or program. It is a low-fat declaration that writes type into the symbol table.
As previously stated, the added complexity of another syntax construct, and a new lexeme or keyword. A further complication is that after a forward method is parsed, and entered into the symbol table, a post-check requires storing all forward method declarations, and verifying that an actual method was declared exactly but later on in the class.
Another semantic twist is that a forward semantic declaration would require a uniqueness (not declared before), and that an actual method declaration does not proceed the forward method declaration (not declared exactly). Instead of simplifying semantics at the cost and trade-off of added lexical and syntactic elements and processing, more semantic complexity is added in the process.
Zero Sum Gain Forward
The result in the compiler design is zero sum (to borrow a term from game theory), so in simplifying of the semantics the complexity has increased in all three phases: lexical, syntax, and semantic.
The simpler approach (and simplicity is better than complexity without any real benefit) is to implicitly require declaration before use, and have the compiler flag a semantic error if an expected attribute or method is not in the symbol table to annotate the type. Of course, this approach is under the requirement of a one pass compiler, for a two pass compiler it would be superfluous.
The real question and the subsequent issues that follow is one pass or two pass, which are driven by the design of the Mynx programming language. In a strange way, its almost a vicious circle with feedback from the design of the compiler design by the compiler writer impacts the design of the language and the programming language designer. The trade-off is that language design complexity is inversely related to the compiler design complexity.
In this case, I am doing both so it is not separate people, but the design issues even in the same head of one person are paradoxical and counter-intuitive. The eventual goal is to find a point of equilibrium between the language design and the compiler design.
As a philosophy professor once might have said, "A long contemplative meditation upon the problem is necessitated."
Labels: annotation semantics, context semantic, language complexity, programming language design, programming language features, semantic analysis, semantic check

<< Home