|
@@ -28,7 +28,13 @@ interface
|
|
uses
|
|
uses
|
|
symsym, symdef;
|
|
symsym, symdef;
|
|
|
|
|
|
|
|
+ { Read the formal declaration in procedure/function/method "headers"
|
|
|
|
+ and in the main program }
|
|
procedure read_formal_decs;
|
|
procedure read_formal_decs;
|
|
|
|
+
|
|
|
|
+ { Read the formal declaration in class declarations }
|
|
|
|
+ procedure read_formal_decs_in_class;
|
|
|
|
+
|
|
|
|
|
|
implementation
|
|
implementation
|
|
|
|
|
|
@@ -58,7 +64,7 @@ implementation
|
|
;
|
|
;
|
|
|
|
|
|
|
|
|
|
- procedure read_proposition; forward;
|
|
|
|
|
|
+ procedure read_definition; forward;
|
|
procedure read_specvar; forward;
|
|
procedure read_specvar; forward;
|
|
procedure read_precondition; forward;
|
|
procedure read_precondition; forward;
|
|
procedure read_postcondition; forward;
|
|
procedure read_postcondition; forward;
|
|
@@ -86,7 +92,7 @@ implementation
|
|
if upcase(pattern)='DEF' then
|
|
if upcase(pattern)='DEF' then
|
|
begin
|
|
begin
|
|
consume(_ID);
|
|
consume(_ID);
|
|
- read_proposition;
|
|
|
|
|
|
+ read_definition;
|
|
end
|
|
end
|
|
else if upcase(pattern)='SPECVAR' then
|
|
else if upcase(pattern)='SPECVAR' then
|
|
begin
|
|
begin
|
|
@@ -129,72 +135,103 @@ implementation
|
|
|
|
|
|
end; { procedure read_formal_decs }
|
|
end; { procedure read_formal_decs }
|
|
|
|
|
|
- procedure read_proposition;
|
|
|
|
|
|
+ procedure read_definition;
|
|
var
|
|
var
|
|
- prop_name : string;
|
|
|
|
- expr : tnode;
|
|
|
|
- vs : tabstractvarsym;
|
|
|
|
|
|
+ def_name : string;
|
|
|
|
+ def_type : ttype;
|
|
|
|
+ def_expr : tnode;
|
|
|
|
+ def : tabstractvarsym;
|
|
|
|
+ type_given : boolean;
|
|
|
|
+ prev_ignore_equal : boolean;
|
|
begin
|
|
begin
|
|
- { parse P : expression }
|
|
|
|
|
|
+ { parse A[,A]*, where A::= P [: TYPE ] = EXPRESSION }
|
|
repeat
|
|
repeat
|
|
- prop_name:=pattern;
|
|
|
|
|
|
+ def_name:=pattern;
|
|
consume(_ID);
|
|
consume(_ID);
|
|
- consume(_COLON);
|
|
|
|
- expr:=comp_expr_in_formal_context(true);
|
|
|
|
- do_resulttypepass(expr);
|
|
|
|
- if not is_boolean(expr.resulttype.def) then
|
|
|
|
|
|
+
|
|
|
|
+ if try_to_consume(_COLON) then
|
|
begin
|
|
begin
|
|
- Message1(type_e_boolean_expr_expected, expr.resulttype.def.typename);
|
|
|
|
- exit;
|
|
|
|
- end;
|
|
|
|
- if not(symtablestack.symtabletype in [localsymtable,globalsymtable]) then
|
|
|
|
|
|
+ prev_ignore_equal:=ignore_equal;
|
|
|
|
+ ignore_equal:=true;{ Signals to read_type to ignore the = token }
|
|
|
|
+ read_type(def_type, '', false);
|
|
|
|
+ ignore_equal:=prev_ignore_equal;
|
|
|
|
+ type_given:=true;
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ type_given:=false;
|
|
|
|
+
|
|
|
|
+ consume(_EQUAL);
|
|
|
|
+
|
|
|
|
+ def_expr:=comp_expr_in_formal_context(true);
|
|
|
|
+ do_resulttypepass(def_expr);
|
|
|
|
+
|
|
|
|
+ if type_given then
|
|
|
|
+ { Match the given type and the type of the expression }
|
|
|
|
+ inserttypeconv(def_expr, def_type)
|
|
|
|
+ else
|
|
|
|
+ { Use the computed type of the expression }
|
|
|
|
+ def_type:=def_expr.resulttype;
|
|
|
|
+
|
|
|
|
+ if not(symtablestack.symtabletype in [localsymtable,globalsymtable,staticsymtable]) then
|
|
begin
|
|
begin
|
|
{ TODO : more descriptive error message }
|
|
{ TODO : more descriptive error message }
|
|
raise EInvalidAnnotation.Create('Proposition definition outside local '+
|
|
raise EInvalidAnnotation.Create('Proposition definition outside local '+
|
|
'or global declaration context');
|
|
'or global declaration context');
|
|
end;
|
|
end;
|
|
- vs:=tspecvarsym.create(prop_name, expr.resulttype { Boolean }, expr);
|
|
|
|
- symtablestack.insert(vs);
|
|
|
|
|
|
+ def:=tdefinitionsym.create(def_name, def_type, def_expr);
|
|
|
|
+ symtablestack.insert(def);
|
|
until not try_to_consume(_COMMA);
|
|
until not try_to_consume(_COMMA);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure read_specvar;
|
|
procedure read_specvar;
|
|
var
|
|
var
|
|
|
|
+ sv : tspecvarsym;
|
|
sv_name : string;
|
|
sv_name : string;
|
|
sv_type : ttype;
|
|
sv_type : ttype;
|
|
sv_expr : tnode;
|
|
sv_expr : tnode;
|
|
- sv : tabstractvarsym;
|
|
|
|
type_given : boolean;
|
|
type_given : boolean;
|
|
prev_ignore_equal : boolean;
|
|
prev_ignore_equal : boolean;
|
|
begin
|
|
begin
|
|
|
|
+ { parse A[,A]* where A::= ID[:TYPE] = EXPRESSION }
|
|
repeat
|
|
repeat
|
|
- { parse P [: type] = expression }
|
|
|
|
sv_name:=pattern;
|
|
sv_name:=pattern;
|
|
consume(_ID);
|
|
consume(_ID);
|
|
- { Is a type given ? }
|
|
|
|
|
|
+
|
|
if try_to_consume(_COLON) then
|
|
if try_to_consume(_COLON) then
|
|
begin
|
|
begin
|
|
|
|
+ type_given:=true;
|
|
prev_ignore_equal:=ignore_equal;
|
|
prev_ignore_equal:=ignore_equal;
|
|
- ignore_equal:=true; { Signals to read_type to ignore the = token }
|
|
|
|
|
|
+ ignore_equal:=true; { Signals to read_type that the = token
|
|
|
|
+ should be ignored }
|
|
read_type(sv_type, '', false);
|
|
read_type(sv_type, '', false);
|
|
ignore_equal:=prev_ignore_equal;
|
|
ignore_equal:=prev_ignore_equal;
|
|
- type_given:=true;
|
|
|
|
end
|
|
end
|
|
else
|
|
else
|
|
type_given:=false;
|
|
type_given:=false;
|
|
-
|
|
|
|
|
|
+
|
|
consume(_EQUAL);
|
|
consume(_EQUAL);
|
|
- { Parse the expression }
|
|
|
|
- sv_expr:=comp_expr(true);
|
|
|
|
|
|
+
|
|
|
|
+ sv_expr:=comp_expr_in_formal_context(true);
|
|
do_resulttypepass(sv_expr);
|
|
do_resulttypepass(sv_expr);
|
|
|
|
+
|
|
if type_given then
|
|
if type_given then
|
|
{ Match the given type and the type of the expression }
|
|
{ Match the given type and the type of the expression }
|
|
inserttypeconv(sv_expr, sv_type)
|
|
inserttypeconv(sv_expr, sv_type)
|
|
else
|
|
else
|
|
- { Set the type to the type of the expression }
|
|
|
|
|
|
+ { Use the computed type of the expression }
|
|
sv_type:=sv_expr.resulttype;
|
|
sv_type:=sv_expr.resulttype;
|
|
|
|
+
|
|
|
|
+ if not(symtablestack.symtabletype in [localsymtable,globalsymtable,staticsymtable]) then
|
|
|
|
+ raise EInvalidAnnotation.Create('Specvars can only be defined in local or global contexts');
|
|
|
|
+
|
|
sv:=tspecvarsym.create(sv_name, sv_type, sv_expr);
|
|
sv:=tspecvarsym.create(sv_name, sv_type, sv_expr);
|
|
symtablestack.insert(sv);
|
|
symtablestack.insert(sv);
|
|
|
|
+
|
|
|
|
+ if (not assigned(current_procinfo)) or (not assigned(current_procinfo.procdef)) then
|
|
|
|
+ raise EInvalidAnnotation.Create('Specvars cannot be defined here');
|
|
|
|
+
|
|
|
|
+ current_procinfo.procdef.specvars.Add(sv);
|
|
|
|
+
|
|
until not try_to_consume(_COMMA);
|
|
until not try_to_consume(_COMMA);
|
|
end;
|
|
end;
|
|
|
|
|
|
@@ -203,7 +240,7 @@ implementation
|
|
var
|
|
var
|
|
expr : tnode;
|
|
expr : tnode;
|
|
begin
|
|
begin
|
|
- consume(_COLON);
|
|
|
|
|
|
+ consume(_EQUAL);
|
|
expr:=comp_expr_in_formal_context(true);
|
|
expr:=comp_expr_in_formal_context(true);
|
|
{ Check here the result type of the expression.
|
|
{ Check here the result type of the expression.
|
|
This will be checked later on as well (after conversion to "assert"),
|
|
This will be checked later on as well (after conversion to "assert"),
|
|
@@ -225,7 +262,7 @@ implementation
|
|
var
|
|
var
|
|
expr : tnode;
|
|
expr : tnode;
|
|
begin
|
|
begin
|
|
- consume(_COLON);
|
|
|
|
|
|
+ consume(_EQUAL);
|
|
expr:=comp_expr_in_formal_context(true);
|
|
expr:=comp_expr_in_formal_context(true);
|
|
{ Check here the result type of the expression.
|
|
{ Check here the result type of the expression.
|
|
This will be checked later on as well (after conversion to "assert"),
|
|
This will be checked later on as well (after conversion to "assert"),
|
|
@@ -249,7 +286,7 @@ implementation
|
|
evald : tnode;
|
|
evald : tnode;
|
|
rst : tnode;
|
|
rst : tnode;
|
|
begin
|
|
begin
|
|
- consume(_COLON);
|
|
|
|
|
|
+ consume(_EQUAL);
|
|
{ Proposition variables are not allowed here }
|
|
{ Proposition variables are not allowed here }
|
|
expr:=comp_expr(true);
|
|
expr:=comp_expr(true);
|
|
{ Convert this to "Result = expr" }
|
|
{ Convert this to "Result = expr" }
|
|
@@ -264,6 +301,53 @@ implementation
|
|
current_procinfo.procdef.postcondition:=evald;
|
|
current_procinfo.procdef.postcondition:=evald;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+
|
|
|
|
+ procedure read_formal_decs_in_class;
|
|
|
|
+
|
|
|
|
+ var
|
|
|
|
+ inv_name : string;
|
|
|
|
+ inv_expr : tnode;
|
|
|
|
+
|
|
|
|
+ begin
|
|
|
|
+ if not (try_to_consume(_CLOSE_FORMAL)) then
|
|
|
|
+ begin
|
|
|
|
+ try
|
|
|
|
+ if (upcase(pattern)<>'INV') then
|
|
|
|
+ raise EInvalidAnnotation.Create('inv expected');
|
|
|
|
+ consume(_ID);
|
|
|
|
+
|
|
|
|
+ inv_name:=pattern;
|
|
|
|
+ consume(_ID);
|
|
|
|
+
|
|
|
|
+ consume(_EQUAL);
|
|
|
|
+
|
|
|
|
+ inv_expr:=comp_expr_in_formal_context_class_header(true);
|
|
|
|
+
|
|
|
|
+ do_resulttypepass(inv_expr);
|
|
|
|
+ if not is_boolean(inv_expr.resulttype.def) then
|
|
|
|
+ raise EInvalidAnnotation.Create('boolean expression expected');
|
|
|
|
+
|
|
|
|
+ if assigned(aktobjectdef.invariant) then
|
|
|
|
+ aktobjectdef.invariant:=caddnode.create(andn,
|
|
|
|
+ aktobjectdef.invariant,
|
|
|
|
+ inv_expr)
|
|
|
|
+ else
|
|
|
|
+ aktobjectdef.invariant:=inv_expr;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ consume(_CLOSE_FORMAL);
|
|
|
|
+ except
|
|
|
|
+ on e: EInvalidAnnotation do
|
|
|
|
+ begin
|
|
|
|
+ { Consume the whole annotation }
|
|
|
|
+ while token<>_CLOSE_FORMAL do
|
|
|
|
+ consume(token);
|
|
|
|
+ consume(_CLOSE_FORMAL);
|
|
|
|
+ Message1(parser_e_invalid_formal_annotation, e.message);
|
|
|
|
+ end; { on EInvalidAnnotation }
|
|
|
|
+ end; { try..except }
|
|
|
|
+ end; { if not try_to_consume(_CLOSE_FORMAL) }
|
|
|
|
+ end;
|
|
end.
|
|
end.
|
|
|
|
|
|
|
|
|