(* Copyright (C) 1992, Digital Equipment Corporation *) (* All rights reserved. *) (* See the file COPYRIGHT for a full description. *) (* *) (* Last modified on Tue Jan 28 13:17:28 PST 1997 by heydon *) (* modified on Fri Aug 7 21:54:06 PDT 1992 by myers *) MODULE JunoChkBNF; IMPORT JunoAST, JunoCompileErr, JunoASTUtils; PROCEDURE TotalCmd(cmd: JunoAST.Cmd) RAISES {JunoCompileErr.Error} = BEGIN TYPECASE cmd OF JunoAST.Skip, JunoAST.Abort, JunoAST.Halt => (* SKIP *) | JunoAST.Else (c) => PartialCmd(c.c1); TotalCmd(c.c2) | JunoAST.Proj (c) => DefinedHints(c.vars); TotalCmd(c.body) | JunoAST.Seq (c) => TotalCmd(c.c1); TotalCmd(c.c2) | JunoAST.GroupedCmd (c) => TotalCmd(c.body); | JunoAST.Assign (c) => QIdList(c.vars); ExprList(c.exprs) | JunoAST.ProcCall (c) => QIdList(c.inouts); ExprList(c.ins); | JunoAST.Do (c) => PartialCmd(c.body); | JunoAST.If (c) => PartialCmd(c.body); | JunoAST.Save (c) => TotalCmd(c.body); ELSE ExpectedError("Total Command", cmd) END END TotalCmd; PROCEDURE DefinedHints(vars: JunoAST.NearVarList) RAISES {JunoCompileErr.Error} = (* Raises "Error" if any of the variables in "vars" is hinted with an expression that could be undefined. *) VAR l := vars.head; BEGIN WHILE l # NIL DO IF l.hint # JunoAST.NilExpr AND NOT JunoASTUtils.AlwaysDefined(l.hint) THEN ExpectedError("Total Command", vars) END; l := l.next END END DefinedHints; PROCEDURE PartialCmd(cmd: JunoAST.Cmd) RAISES {JunoCompileErr.Error} = BEGIN TYPECASE cmd OF JunoAST.Else (c) => PartialCmd(c.c1); PartialCmd(c.c2) | JunoAST.Proj (c) => PartialCmd(c.body); | JunoAST.Guard (c) => Formula(c.grd); PartialCmd(c.body); | JunoAST.Seq (c) => PartialCmd(c.c1); TotalCmd(c.c2) | JunoAST.Query (c) => Formula(c.f) | JunoAST.GroupedCmd (c) => PartialCmd(c.body); ELSE TRY TotalCmd(cmd) EXCEPT JunoCompileErr.Error (e) => IF e.ast = cmd THEN ExpectedError("Partial Command", cmd) ELSE RAISE JunoCompileErr.Error(e) END END END END PartialCmd; PROCEDURE Formula(form: JunoAST.Formula) RAISES {JunoCompileErr.Error} = BEGIN TYPECASE form OF JunoAST.Or (f) => Formula(f.f1); Formula(f.f2); | JunoAST.And (f) => Formula(f.f1); Formula(f.f2); | JunoAST.Not (f) => Formula(f.f); | JunoAST.True, JunoAST.False => (* SKIP *) | JunoAST.Exists (f) => Formula(f.f) | JunoAST.BIUPred (f) => Expr(f.e) | JunoAST.Relation (f) => Expr(f.e1); Expr(f.e2) | JunoAST.Call => PredicateCall(form) | JunoAST.GroupedExpr (f) => Formula(f.expr) ELSE ExpectedError("Formula", form) END END Formula; PROCEDURE PredicateCall(call: JunoAST.Call) RAISES {JunoCompileErr.Error} = BEGIN IF call.inouts.size # 0 THEN ExpectedError("Predicate Call", call); END; ExprList(call.ins) END PredicateCall; PROCEDURE Expr(expr: JunoAST.Expr) RAISES {JunoCompileErr.Error} = BEGIN TYPECASE expr OF JunoAST.Rel (e) => Expr(e.e1); Expr(e.e2) | JunoAST.BuiltInAddFunc (e) => Expr(e.e1); Expr(e.e2) | JunoAST.BuiltInMulFunc (e) => Expr(e.e1); Expr(e.e2) | JunoAST.UMinus (e) => Expr(e.e); | JunoAST.AtomicExpr => (* SKIP *) | JunoAST.BIUFunc (e) => Expr(e.e) | JunoAST.BIBFunc (e) => Expr(e.e1); Expr(e.e2) | JunoAST.List (e) => ExprList(e.elts) | JunoAST.Call (e) => QIdList(e.inouts); ExprList(e.ins) | JunoAST.GroupedExpr (e) => Expr(e.expr) ELSE ExpectedError("Expression", expr) END END Expr; PROCEDURE QIdList(qids: JunoAST.ExprList) RAISES {JunoCompileErr.Error} = VAR curr := qids.head; BEGIN WHILE curr # NIL DO IF NOT ISTYPE(curr.expr, JunoAST.QId) THEN ExpectedError("QID", curr.expr) END; curr := curr.next; END END QIdList; PROCEDURE ExprList(exprs: JunoAST.ExprList) RAISES {JunoCompileErr.Error} = VAR curr := exprs.head; BEGIN WHILE curr # NIL DO Expr(curr.expr); curr := curr.next; END END ExprList; PROCEDURE ExpectedError(t: TEXT; ast: JunoAST.T) RAISES {JunoCompileErr.Error} = BEGIN JunoCompileErr.Raise("Expected \"" & t & "\"", ast) END ExpectedError; BEGIN END JunoChkBNF.