Eli   Documents

General Information

 o Eli: Translator Construction Made Easy
 o Global Index
 o Frequently Asked Questions
 o Typical Eli Usage Errors

Tutorials

 o Quick Reference Card
 o Guide For new Eli Users
 o Release Notes of Eli
 o Tutorial on Name Analysis
 o Tutorial on Scope Graphs
 o Tutorial on Type Analysis
 o Typical Eli Usage Errors

Reference Manuals

 o User Interface
 o Eli products and parameters
 o LIDO Reference Manual
 o Typical Eli Usage Errors

Libraries

 o Eli library routines
 o Specification Module Library

Translation Tasks

 o Lexical analysis specification
 o Syntactic Analysis Manual
 o Computation in Trees

Tools

 o LIGA Control Language
 o Debugging Information for LIDO
 o Graphical ORder TOol

 o FunnelWeb User's Manual

 o Pattern-based Text Generator
 o Property Definition Language
 o Operator Identification Language
 o Tree Grammar Specification Language
 o Command Line Processing
 o COLA Options Reference Manual

 o Generating Unparsing Code

 o Monitoring a Processor's Execution

Administration

 o System Administration Guide

Mail Home

Type Analysis

Previous Chapter Next Chapter Table of Contents


Error Reporting in Type Analysis

Language-dependent error reporting involves checks based on the types associated with program constructs by the computations specified in earlier chapters. For example, object-oriented languages differ in their requirements for overriding methods when extending a class definition. One possibility is to require that the type of each parameter of the overriding method be a supertype of the corresponding parameter type of the overridden method, and that the result type of the overriding method be a subtype of the result type of the overridden method. The type analysis modules will establish the complete signatures of both methods, and the subtype/supertype relation among all type pairs. Thus only the actual check remains to be written.

Some errors make it impossible to associate any type with a program construct, and these are reported by the modules. Operations are also made available to support detection of incorrect typing.

Verifying typed identifier usage

An applied occurrence of an identifier that purports to represent a typed entity inherits the TypedIdUse role. The value of its Type attribute should not be NoKey, and the identifier itself should not be a type identifier. Both of these conditions can be checked by inheriting the ChkTypedUseId role:

SYMBOL ExpIdUse INHERITS ChkTypedUseId END;

If the identifier `id' at an ExpIdUse node is bound, but the type is unknown, the ChkTypedUseId computation will issue the following report at the source coordinates of `id'

Must denote a typed object: `id'

If the identifier `id' at an ExpIdUse node is a type identifier, the report would be:

Type identifier not allowed: `id'

Verifying type identifier usage

Both defining and applied occurrences of type identifiers can be checked for validity. In each case, the value of the Type attribute must be a definition table key whose IsType property has the value 1. Two roles are available for this purpose:

ChkTypeDefDefId
reports an error if the Type attribute does not refer to a type, or if the type refers to itself.

ChkTypeDefUseId
reports an error if the Type attribute does not refer to a type.

Verifying type consistency within an expression

The Expression module provides default error reporting associated with the following roles:

ExpressionSymbol
Condition:
`e'.Type is not acceptable as `e'.Required.
Message:
`Incorrect type for this context'
Override symbols:
ExpMsg, ExpErr, ExpError

  • OperatorSymbol
    Condition:
    The indication is valid but no operator could be identified.
    Message:
    `Incorrect operand type(s) for this operator'
    Override symbols:
    OprMsg, OprErr, OprError

  • OpndExprListRoot
    Condition:
    The function requires more arguments than are present.
    Message:
    `Too few arguments'
    Override symbols:
    LstMsg, LstErr, LstError

  • OpndExprListElem
    Condition:
    The function requires fewer arguments than are present.
    Message:
    `Too many arguments'
    Override symbols:
    ArgMsg, ArgErr, ArgError
  • This error reporting can be changed by overriding computations for the `xxx'Msg attribute. The `xxx'Err attribute has the value 1 if the error condition is met, 0 otherwise. Thus the overriding computation might be of the form:

    `s'.`xxx'Msg=
      IF(`s'.`xxx'Err,message(ERROR,"My report",0,COORDREF));
    

    Because `s'.`xxx'Msg is of type VOID, you can remove a report completely by setting `s'.`xxx'Msg to "no".

    If you wish to override the message in every context, write the overriding computation as a symbol computation in the lower context of the override symbol specified above. In this case, `xxx' would be SYNT. Here is an example, changing the error report for invalid operators in all contexts:

    SYMBOL OprError COMPUTE
      SYNT.OprMsg=
        IF(SYNT.OprErr,message(ERROR,"Invalid operator",0,COORDREF));
    END;
    

    If you wish to override the message in a few specific contexts, write the overriding computation as a rule computation in the lower context of a symbol inheriting the computational role. In this case, `xxx' would be the symbol on the left-hand side of the rule. Here is an example, changing the standard expression error report to be more specific for function arguments:

    RULE: Actual ::= Expr COMPUTE
      Actual.ExpMsg=
        IF(Actual.ExpErr,message(ERROR,"Wrong argument type",0,COORDREF));
    END;
    

    Support for context checking

    As noted in the previous section, OperatorSymbol role computations normally report an error when an indication is valid but no operator can be identified. The Expression module exports two context-dependent rule computations for use when an expression node has no children playing that role. One computation tests the indication and the other tests the operator:

    BadIndication
    Yields 1 if the operator indication supplied by Indication is unknown, 0 otherwise.

    BadOperator
    Yields 1 if the indication is valid but no operator can be selected from that indication's set, 0 otherwise.

    Consider an expression in which a function is applied to arguments (see Functions as typed entities):

    SYMBOL Expr    INHERITS ExpressionSymbol END;
    SYMBOL Actuals INHERITS OpndExprListRoot END;
    
    RULE: Expr ::= Expr '(' Actuals ')' COMPUTE
      ListContext(Expr[1],,Actuals);
      Indication(GetInvoker(Expr[2].Type,NoKey));
      IF(BadIndication,
        message(ERROR,"Invalid function",0,COORDREF));
    END;
    

    Suppose that, because of a programming error, Expr[2] does not deliver a function type. In that case, Expr[2].Type would not have the Invoker property, and BadIndication would yield 1. Alternatively, Expr[2] might deliver a function whose signature does not match the context. Because the indication has only a singleton operator set, that operator will be selected regardless of the context. Errors will then be reported by the default mechanisms as an incorrect number of arguments, arguments of incorrect types, or result incorrect for the context.

    Now consider the array access expression (see Operators with explicit operands):

    SYMBOL Subscript INHERITS ExpressionSymbol END;
    
    RULE: Expr ::= Expr '[' Subscript ']' COMPUTE
      DyadicContext(Expr[1],,Expr[2],Subscript);
      Indication(indexInd),
      IF(BadOperator,
        message(ERROR,"Invalid array reference",0,COORDREF));
    END;
    

    Suppose that, because of a programming error, Expr[2] does not deliver an array type. In that case, there would be no operator in indexInd's operator set whose left operand was the type returned by Expr[2] and BadOperator would yield 1.

    It is sometimes useful to be able to check whether one type is acceptable as another outside of the situations covered in the previous section. Let `from' and `to' be definition table keys representing types. IsCoercible(`from',`to') yields 1 if a value of type `from' is acceptable wherever an value of type `to' is required; it yields 0 otherwise.

    For example, consider a cast involving a reference type in Java. The cast is known to be correct at compile time if a value is being cast to its superclass. If the value is being cast to one of its subclasses, however, a run-time check is required. Thus the compiler must accept such a cast both when the value is acceptable as a value of the cast type and when a value of the cast type is acceptable as a value of the type being cast:

    RULE: Expression ::= '(' Expression ')' Expression COMPUTE
      IF(AND(
          NOT(IsCoercible(Expression[2].Type,Expression[3].Type)),
          NOT(IsCoercible(Expression[3].Type,Expression[2].Type))),
        message(ERROR,"Invalid cast",0,COORDREF));
    END;
    


    Previous Chapter Next Chapter Table of Contents