section‹Parser› theory Parser imports"../basic/Syntax" begin
subsection‹Tagging› text‹We define a few tag constants.
They are inserted by the parser, and tag certain situations,
like parameter passing or inlined commands. ›
definition Inline :: "com ==> com"where"Inline c = c"
definition Params :: "com ==> com"where"Params c ≡ c"
text‹Assignment commands to assign the return value.
The VCG will add a renaming, such that the assigned variable name rather
the ‹G_ret› will be used for the VCs› definition"AssignIdx_retv x i rv ≡ AssignIdx x i (V rv)" definition"ArrayCpy_retv x rv ≡ ArrayCpy x rv"
abbreviation"Assign_retv x rv ≡ AssignIdx_retv x (N 0) rv"
subsection‹Parser for IMP Programs›
text‹The parser also understands annotated programs.
However, the basic parser will leave the annotations uninterpreted,
and it's up to the client of the parser to interpret them. ›
abbreviation (input) While_Annot :: "'a ==> bexp ==> com ==> com" where"While_Annot I ≡ While"
(* Note: Still a very early prototype *)
abbreviation (input) VARIABLEI :: "string ==> string"where"VARIABLEI x ≡ x"(* Used to mark integer variables *) abbreviation (input) VARIABLEA :: "string ==> string"where"VARIABLEA x ≡ x"(* Used to mark array variables *)
ML ‹
structure Term_Annot : sig
(* Annotate terms *)
val annotate_term: term -> string * Position.T -> term
val dest_annotated_term: term -> (string * Position.T) * term
(* Annotation = annotated dummy term *)
val annotation: string * Position.T -> term
val dest_annotation: term -> term
(* Checking for annotations in Term *)
val is_annotated_term: term -> bool
val has_annotations: term -> bool
(* Removing annotations *)
val strip_annotations: term -> term (* Replaces annotated terms by dummy term *)
val strip_annotated_terms: term -> term
(* Parsing *) (* Parse cartouche (independent of term annotations)*)
val parse_cartouche: (string * Position.T) parser (* Parse cartouche into annotation *)
val parse_annotation: term parser (* Parse cartouche into annotation of syntax constant (used to get typed annotations) *)
val parse_annotate: string -> term parser
(* Read term from cartouche and position *)
val read_term: Proof.context -> string * Position.T -> term
(* Read annotation part of annotated term as term *)
val read_annotation_as_term: Proof.context -> term -> term * term end = struct fun annotate_term t (str,pos) = let
val pos = Free (Term_Position.encode [Term_Position.no_syntax pos],dummyT)
val str = Free (str,dummyT)
val c = Const (@{syntax_const "_annotated_term"}, dummyT --> dummyT --> dummyT --> dummyT) in
c$t$str$pos end
fun dest_annotated_term (Const (@{syntax_const "_annotated_term"},_)$t$Free (str,_)$Free (pos,_)) = let
val pos = case Term_Position.decode pos of
[] => raise TERM ("dest_term_annot: invalid pos",[t])
| {pos, ...} :: _ => pos in ((str,pos),t) end
| dest_annotated_term t = raise TERM("dest_annot",[t])
val is_annotated_term = can dest_annotated_term
val has_annotations = Term.exists_subterm is_annotated_term
val annotation = annotate_term Term.dummy
val dest_annotation = dest_annotated_term #> #2
val parse_cartouche = Parse.position Parse.cartouche >> apfst cartouche
val parse_annotation = parse_cartouche >> annotation
fun parse_annotate n = parse_cartouche >> annotate_term (Const (n,dummyT))
fun read_term ctxt spos = let
val tk = Symbol_Pos.explode spos |> Token.read_cartouche in
read_term_tk ctxt tk end
fun read_annotation_as_term ctxt = dest_annotated_term #>> read_term ctxt
(* Strip one level of term annotations. *) fun strip_annotations (Const (@{syntax_const "_annotated_term"},_)$t$_$_) = t
| strip_annotations (a$b) = strip_annotations a $ strip_annotations b
| strip_annotations (Abs (x,T,t)) = Abs (x,T,strip_annotations t)
| strip_annotations t = t
fun strip_annotated_terms (Const (@{syntax_const "_annotated_term"},_)$_$_$_) = Term.dummy
| strip_annotated_terms (a$b) = strip_annotated_terms a $ strip_annotated_terms b
| strip_annotated_terms (Abs (x,T,t)) = Abs (x,T,strip_annotated_terms t)
| strip_annotated_terms t = t
end ›
ML ‹ structureIMP_Syntax=struct funantft=( exists_typeis_TFreetandalsoraiseTERM("Thiswon'tsupportpolymorphismincommands!",[t]); t)
valmk_varname=HOLogic.mk_string
(*fun mk_aexp_V x = antf(@{term V})$x funmk_aexp_Vidxxi=@{constVidx}$x$i valmk_aexp_V'=mk_aexp_Vomk_var
*)
fun mk_aexp_const i = 🍋‹N› $ HOLogic.mk_number @{typ int} i
fun mk_var_i x = Const (@{const_abbrev VARIABLEI}, dummyT) $ mk_varname x fun mk_var_a x = Const (@{const_abbrev VARIABLEA}, dummyT) $ mk_varname x
(* Caution: This must match the Isabelle function is_global! *) fun is_global "" = true
| is_global s = nth_string s 0 = "G"
val is_local = not o is_global
(* Expressions *)
datatype rval = RV_AEXP of term | RV_VAR of string fun rv_t (RV_AEXP t) = t
| rv_t (RV_VAR x) = 🍋‹Vidx› $ mk_var_i x $ mk_aexp_const 0
val rv_var = RV_VAR fun rv_var_idx x i = RV_AEXP (🍋‹Vidx› $ mk_var_a x $ rv_t i)
(*fun rv_int t = RV_AEXP (@{const N} $ (rv_t t))*)
val rv_int' = RV_AEXP o mk_aexp_const
fun rv_unop f t = RV_AEXP (f $ rv_t t) fun rv_binop f a b = RV_AEXP (f $ rv_t a $ rv_t b)
fun rv_BC t = RV_AEXP 🍋‹Bc for t› fun rv_BC' true = rv_BC 🍋‹True›
| rv_BC' false = rv_BC 🍋‹False›
fun rv_not t = RV_AEXP 🍋‹Not for ‹rv_t t››
(* TODO: Add other constructors here *)
(* TODO: Interface for variable tagging mk_var_xxx is not clear! *)
(* Commands*)
val mk_Skip = 🍋‹SKIP› fun mk_Assign x t = antf(@{term Assign})$x$t fun mk_AssignIdx x i t = @{Const AssignIdx}$x$i$t fun mk_ArrayCpy d s = 🍋‹ArrayCpy for d s› fun mk_ArrayInit d = 🍋‹ArrayClear for d› fun mk_Scope c = 🍋‹Scope for c› fun mk_Seq c1 c2 = 🍋‹Seq for c1 c2›
fun mk_Inline t = 🍋‹Inline for t› fun mk_Params t = 🍋‹Params for t›
val While_Annot_c = Const (@{const_abbrev While_Annot}, dummyT --> @{typ"bexp ==> com ==> com"})
fun mk_If b t e = 🍋‹If for ‹rv_t b› t e› fun mk_While_annot annots b c = While_Annot_c $ annots $ rv_t b $ c
fun mk_pcall name = 🍋‹PCall for ‹HOLogic.mk_string name››
(* Derived Constructs *)
datatype varkind = VAL | ARRAY
type impvar = string * varkind
datatype lval = LV_IDX of string * term | LV_VAR of string
fun list_Seq [] = mk_Skip
| list_Seq [c] = c
| list_Seq (c::cs) = mk_Seq c (list_Seq cs)
fun mk_AssignIdx_retv x i y = 🍋‹AssignIdx_retv for x i y› fun mk_ArrayCpy_retv d s = 🍋‹ArrayCpy_retv for d s› fun mk_Assign_retv x t = antf(@{term Assign_retv})$x$t
fun mk_assign_from_retv (LV_IDX (x,i)) y = mk_AssignIdx_retv (mk_var_a x) i (mk_var_i y)
| mk_assign_from_retv (LV_VAR x) y = mk_ArrayCpy_retv (mk_var_i x) (mk_var_i y)
fun param_varnames n = map (fn i => "G_par_"^Int.toString i) (1 upto n) fun zip_with_param_names xs = (param_varnames (length xs)) ~~ xs fun zip_with_param_lvs xs = map LV_VAR (param_varnames (length xs)) ~~ xs fun zip_with_param_rvs xs = map RV_VAR (param_varnames (length xs)) ~~ xs
fun ret_varnames n = map (fn i => "G_ret_"^Int.toString i) (1 upto n) fun zip_with_ret_names xs = (ret_varnames (length xs)) ~~ xs fun zip_with_ret_lvs xs = map LV_VAR (ret_varnames (length xs)) ~~ xs fun zip_with_ret_rvs xs = map RV_VAR (ret_varnames (length xs)) ~~ xs
fun mk_params ress name_t args = let
val param_assigns = zip_with_param_lvs args
|> map (uncurry mk_lr_assign)
val res_assigns = zip_with_ret_names ress
|> map (fn (rv,res) => mk_assign_from_retv res rv)
val res = param_assigns @ [mk_Params name_t] @ res_assigns
|> list_Seq
in
val parse_exp_tab = Inttab.dest #> map snd #> parse_levels
val parse_exp = Context.Proof #> Opr_Data.get #> parse_exp_tab end
(* TODO/FIXME: Going through the Args.term parser feels like a hack *) fun read_term_pos ctxt spos = Args.term (Context.Proof ctxt, [Token.make_string spos]) |> fst
) xs and parse_com xs = (
parse_com1 -- (Scan.unless (Parse.$$$ ";") (Scan.succeed NONE) || Parse.$$$ ";" |-- parse_com >> SOME )
>> (fn (s,SOME t) => IMP_Syntax.mk_Seq s t | (s,NONE) => s)
) xs
in parse_com end
fun parse_all ctxt p src = let
val src = map Token.init_assignable src
val (res,_) = Scan.catch (Scan.finite Token.stopper (p --| Scan.ahead Parse.eof)) src
val rp = map Token.reports_of_value src |> flat
val _ = Context_Position.reports ctxt rp
(* val src = map Token.closure src |> @{print} *) in
res end
val keywords_of_tab : op_decl list Inttab.table -> string list
= Inttab.dest_list #> map (snd#>snd#>fst)
fun keywords ctxt = let
val kws = ctxt |> Context.Proof |> Opr_Data.get |> keywords_of_tab
val kws = (kws @ fixed_keywords)
|> Symtab.make_set |> Symtab.keys
|> map (fn x => ((x,Position.none),Keyword.no_spec)) in
Keyword.add_keywords kws Keyword.empty_keywords end
fun parse_pos_text p ctxt (pos,text) =
Token.explode (keywords ctxt) pos text
|> filter Token.is_proper
|> parse_all ctxt (p ctxt)
fun parse_sympos p ctxt xs = let
val kws = keywords ctxt
val tks = Token.tokenize kws {strict=true} xs
val rp = map (Token.reports kws) tks |> flat (* TODO: More detailed report AFTER parsing! *)
val _ = Context_Position.reports_text ctxt rp in
tks
|> filter Token.is_proper
|> parse_all ctxt (p ctxt) end
fun variables_of t = let fun add (Const (@{const_abbrev VARIABLEI},_)$x) = (Symtab.default (HOLogic.dest_string x,IMP_Syntax.VAL))
| add (Const (@{const_abbrev VARIABLEA},_)$x) = (Symtab.update (HOLogic.dest_string x,IMP_Syntax.ARRAY))
| add (a$b) = add a #> add b
| add (Abs (_,_,t)) = add t
| add _ = I
in
add t Symtab.empty |> Symtab.dest end
fun merge_variables vars = let fun add (x,IMP_Syntax.VAL) = Symtab.default (x,IMP_Syntax.VAL)
| add (x,IMP_Syntax.ARRAY) = Symtab.update (x,IMP_Syntax.ARRAY) in
fold add vars Symtab.empty |> Symtab.dest end
fun parse_command_at ctxt spos = let
val syms = spos |> Symbol_Pos.explode |> Symbol_Pos.cartouche_content
val res = parse_sympos parse_command ctxt syms
val vars = variables_of res in
(vars,res) end
(* From Makarius: Protect a term such that it "survives" the subsequent translation phase *) fun mark_term (Const (c, T)) = Const (Lexicon.mark_const c, T)
| mark_term (Free (x, T)) = Const (Lexicon.mark_fixed x, T)
| mark_term (t $ u) = mark_term t $ mark_term u
| mark_term (Abs (x, T, b)) = Abs (x, T, mark_term b)
| mark_term a = a;
fun cartouche_tr ctxt args = let fun err () = raise TERM ("imp",args)
fun parse spos = let
val (_,t) = parse_command_at ctxt spos
val t = if Term_Annot.has_annotations t then (warning "Stripped annotations from program"; Term_Annot.strip_annotated_terms t) else t
val t = Syntax.check_term ctxt t
|> mark_term in
t end
in
(case args of
[(c as Const (@{syntax_const "_constrain"}, _)) $ Free (s, _) $ p] =>
(case Term_Position.decode_position1 p of
SOME {pos, ...} => c $ parse (s,pos) $ p
| NONE => err ())
| _ => err ()) end
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.