ProgTutorial/Parsing.thy
changeset 241 29d4701c5ee1
parent 240 d111f5988e49
child 244 dc95a56b1953
equal deleted inserted replaced
240:d111f5988e49 241:29d4701c5ee1
   144   val just_h = $$ \"h\" --| $$ \"e\" 
   144   val just_h = $$ \"h\" --| $$ \"e\" 
   145   val input = Symbol.explode \"hello\"  
   145   val input = Symbol.explode \"hello\"  
   146 in 
   146 in 
   147   (just_e input, just_h input)
   147   (just_e input, just_h input)
   148 end"
   148 end"
   149   "((\"e\", [\"l\", \"l\", \"o\"]),(\"h\", [\"l\", \"l\", \"o\"]))"}
   149   "((\"e\", [\"l\", \"l\", \"o\"]), (\"h\", [\"l\", \"l\", \"o\"]))"}
   150 
   150 
   151   The parser @{ML "Scan.optional p x" for p x} returns the result of the parser 
   151   The parser @{ML "Scan.optional p x" for p x} returns the result of the parser 
   152   @{text "p"}, if it succeeds; otherwise it returns 
   152   @{text "p"}, if it succeeds; otherwise it returns 
   153   the default value @{text "x"}. For example:
   153   the default value @{text "x"}. For example:
   154 
   154 
   422   @{ML_response_fake [display,gray] "OuterSyntax.scan Position.none \"hello world\"" 
   422   @{ML_response_fake [display,gray] "OuterSyntax.scan Position.none \"hello world\"" 
   423 "[Token (\<dots>,(Keyword, \"hello\"),\<dots>), 
   423 "[Token (\<dots>,(Keyword, \"hello\"),\<dots>), 
   424  Token (\<dots>,(Space, \" \"),\<dots>), 
   424  Token (\<dots>,(Space, \" \"),\<dots>), 
   425  Token (\<dots>,(Ident, \"world\"),\<dots>)]"}
   425  Token (\<dots>,(Ident, \"world\"),\<dots>)]"}
   426 
   426 
   427   Many parsing functions later on will require spaces, comments and the like
   427   Many parsing functions later on will require white space, comments and the like
   428   to have already been filtered out.  So from now on we are going to use the 
   428   to have already been filtered out.  So from now on we are going to use the 
   429   functions @{ML filter} and @{ML OuterLex.is_proper} to do this. For example:
   429   functions @{ML filter} and @{ML OuterLex.is_proper} to do this. For example:
   430 
   430 
   431 @{ML_response_fake [display,gray]
   431 @{ML_response_fake [display,gray]
   432 "let
   432 "let
   450 "[Token (\<dots>,(Command, \"inductive\"),\<dots>), 
   450 "[Token (\<dots>,(Command, \"inductive\"),\<dots>), 
   451  Token (\<dots>,(Keyword, \"|\"),\<dots>), 
   451  Token (\<dots>,(Keyword, \"|\"),\<dots>), 
   452  Token (\<dots>,(Keyword, \"for\"),\<dots>)]"}
   452  Token (\<dots>,(Keyword, \"for\"),\<dots>)]"}
   453 
   453 
   454   you obtain a list consisting of only one command and two keyword tokens.
   454   you obtain a list consisting of only one command and two keyword tokens.
   455   If you want to see which keywords and commands are currently known to Isabelle, type in
   455   If you want to see which keywords and commands are currently known to Isabelle, 
   456   the following code (you might have to adjust the @{ML print_depth} in order to
   456   type:
   457   see the complete list):
       
   458 
   457 
   459 @{ML_response_fake [display,gray] 
   458 @{ML_response_fake [display,gray] 
   460 "let 
   459 "let 
   461   val (keywords, commands) = OuterKeyword.get_lexicons ()
   460   val (keywords, commands) = OuterKeyword.get_lexicons ()
   462 in 
   461 in 
   463   (Scan.dest_lexicon commands, Scan.dest_lexicon keywords)
   462   (Scan.dest_lexicon commands, Scan.dest_lexicon keywords)
   464 end" 
   463 end" 
   465 "([\"}\", \"{\", \<dots>], [\"\<rightleftharpoons>\", \"\<leftharpoondown>\", \<dots>])"}
   464 "([\"}\", \"{\", \<dots>], [\"\<rightleftharpoons>\", \"\<leftharpoondown>\", \<dots>])"}
       
   465 
       
   466   You might have to adjust the @{ML print_depth} in order to
       
   467   see the complete list.
   466 
   468 
   467   The parser @{ML "OuterParse.$$$"} parses a single keyword. For example:
   469   The parser @{ML "OuterParse.$$$"} parses a single keyword. For example:
   468 
   470 
   469 @{ML_response [display,gray]
   471 @{ML_response [display,gray]
   470 "let 
   472 "let 
   577  Token ((\"bar\", ({line=8, end_line=8}, {line=8})), (Ident, \"bar\"), \<dots>)]"}
   579  Token ((\"bar\", ({line=8, end_line=8}, {line=8})), (Ident, \"bar\"), \<dots>)]"}
   578 
   580 
   579   in which the @{text [quotes] "\\n"} causes the second token to be in 
   581   in which the @{text [quotes] "\\n"} causes the second token to be in 
   580   line 8.
   582   line 8.
   581 
   583 
   582   By using the parser @{ML OuterParse.position} you can decode the positional
   584   By using the parser @{ML OuterParse.position} you can access the token position
   583   information and return it as part of the parsed input. For example
   585   and return it as part of the parser result. For example
   584 
   586 
   585 @{ML_response_fake [display,gray]
   587 @{ML_response_fake [display,gray]
   586 "let
   588 "let
   587   val input = (filtered_input' \"where\")
   589   val input = filtered_input' \"where\"
   588 in 
   590 in 
   589   parse (OuterParse.position (OuterParse.$$$ \"where\")) input
   591   parse (OuterParse.position (OuterParse.$$$ \"where\")) input
   590 end"
   592 end"
   591 "((\"where\", {line=7, end_line=7}), [])"}
   593 "((\"where\", {line=7, end_line=7}), [])"}
   592 
   594 
   681           OuterParse.!!! 
   683           OuterParse.!!! 
   682             (OuterParse.enum1 "|" 
   684             (OuterParse.enum1 "|" 
   683                (SpecParse.opt_thm_name ":" -- OuterParse.prop))) []*}
   685                (SpecParse.opt_thm_name ":" -- OuterParse.prop))) []*}
   684 
   686 
   685 text {*
   687 text {*
   686   Note that the parser does not parse the keyword \simpleinductive, even if it is
   688   Note that the parser must not parse the keyword \simpleinductive, even if it is
   687   meant to process definitions as shown above. The parser of the keyword 
   689   meant to process definitions as shown above. The parser of the keyword 
   688   will be given by the infrastructure that will eventually call @{ML spec_parser}.
   690   will be given by the infrastructure that will eventually call @{ML spec_parser}.
   689   
   691   
   690 
   692 
   691   To see what the parser returns, let us parse the string corresponding to the 
   693   To see what the parser returns, let us parse the string corresponding to the 
   732 
   734 
   733 text {*
   735 text {*
   734   Whenever types are given, they are stored in the @{ML SOME}s. The types are
   736   Whenever types are given, they are stored in the @{ML SOME}s. The types are
   735   not yet used to type the variables: this must be done by type-inference later
   737   not yet used to type the variables: this must be done by type-inference later
   736   on. Since types are part of the inner syntax they are strings with some
   738   on. Since types are part of the inner syntax they are strings with some
   737   encoded information (see previous section). If a syntax translation is
   739   encoded information (see previous section). If a mixfix-syntax is
   738   present for a variable, then it is stored in the @{ML Mixfix} data structure;
   740   present for a variable, then it is stored in the @{ML Mixfix} data structure;
   739   no syntax translation is indicated by @{ML NoSyn}.
   741   no syntax translation is indicated by @{ML NoSyn}.
   740 
   742 
   741   \begin{readmore}
   743   \begin{readmore}
   742   The data structure for syntax annotations is defined in @{ML_file "Pure/Syntax/mixfix.ML"}.
   744   The data structure for mixfix annotations is defined in @{ML_file "Pure/Syntax/mixfix.ML"}.
   743   \end{readmore}
   745   \end{readmore}
   744 
   746 
   745   Lines 3 to 7 in the function @{ML spec_parser} implement the parser for a
   747   Lines 3 to 7 in the function @{ML spec_parser} implement the parser for a
   746   list of introduction rules, that is propositions with theorem annotations
   748   list of introduction rules, that is propositions with theorem annotations
   747   such as rule names and attributes. The introduction rules are propositions
   749   such as rule names and attributes. The introduction rules are propositions
   856   OuterSyntax.local_theory \"foobar\" \"description of foobar\" kind do_nothing
   858   OuterSyntax.local_theory \"foobar\" \"description of foobar\" kind do_nothing
   857 end"}\\
   859 end"}\\
   858   @{text "\<verbclose>"}\\
   860   @{text "\<verbclose>"}\\
   859   \isacommand{end}
   861   \isacommand{end}
   860   \end{graybox}
   862   \end{graybox}
   861   \caption{The file @{text "Command.thy"} is necessary for generating a log 
   863   \caption{This file can be used to generate a log file. This log file in turn can
   862   file. This log file enables Isabelle to generate a keyword file containing 
   864   be used to generate a keyword file containing the command \isacommand{foobar}.
   863   the command \isacommand{foobar}.\label{fig:commandtheory}}
   865   \label{fig:commandtheory}}
   864   \end{figure}
   866   \end{figure}
   865   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   867   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   866 
   868 
   867   For our purposes it is sufficient to use the log files of the theories
   869   For our purposes it is sufficient to use the log files of the theories
   868   @{text "Pure"}, @{text "HOL"} and @{text "Pure-ProofGeneral"}, as well as
   870   @{text "Pure"}, @{text "HOL"} and @{text "Pure-ProofGeneral"}, as well as
   907   @{text [display] "$ isabelle make"}
   909   @{text [display] "$ isabelle make"}
   908 
   910 
   909   If the compilation succeeds, you have finally created all the necessary log files. 
   911   If the compilation succeeds, you have finally created all the necessary log files. 
   910   They are stored in the directory 
   912   They are stored in the directory 
   911   
   913   
   912   @{text [display]  "~/.isabelle/heaps/Isabelle2008/polyml-5.2.1_x86-linux/log"}
   914   @{text [display]  "~/.isabelle/heaps/Isabelle2009/polyml-5.2.1_x86-linux/log"}
   913 
   915 
   914   or something similar depending on your Isabelle distribution and architecture.
   916   or something similar depending on your Isabelle distribution and architecture.
   915   One quick way to assign a shell variable to this directory is by typing
   917   One quick way to assign a shell variable to this directory is by typing
   916 
   918 
   917   @{text [display] "$ ISABELLE_LOGS=\"$(isabelle getenv -b ISABELLE_OUTPUT)\"/log"}
   919   @{text [display] "$ ISABELLE_LOGS=\"$(isabelle getenv -b ISABELLE_OUTPUT)\"/log"}
   935 
   937 
   936   The result is the file @{text "isar-keywords-foobar.el"}. It should contain
   938   The result is the file @{text "isar-keywords-foobar.el"}. It should contain
   937   the string @{text "foobar"} twice.\footnote{To see whether things are fine, check
   939   the string @{text "foobar"} twice.\footnote{To see whether things are fine, check
   938   that @{text "grep foobar"} on this file returns something
   940   that @{text "grep foobar"} on this file returns something
   939   non-empty.}  This keyword file needs to
   941   non-empty.}  This keyword file needs to
   940   be copied into the directory @{text "~/.isabelle/etc"}. To make Isabelle
   942   be copied into the directory @{text "~/.isabelle/etc"}. To make ProofGeneral
   941   aware of this keyword file, you have to start Isabelle with the option @{text
   943   aware of this keyword file, you have to start Isabelle with the option @{text
   942   "-k foobar"}, that is:
   944   "-k foobar"}, that is:
   943 
   945 
   944 
   946 
   945   @{text [display] "$ isabelle emacs -k foobar a_theory_file"}
   947   @{text [display] "$ isabelle emacs -k foobar a_theory_file"}
  1008   argument and then starts a proof in order to prove it. Therefore in Line 13, 
  1010   argument and then starts a proof in order to prove it. Therefore in Line 13, 
  1009   we set the kind indicator to @{ML thy_goal in OuterKeyword}.
  1011   we set the kind indicator to @{ML thy_goal in OuterKeyword}.
  1010 *}
  1012 *}
  1011 
  1013 
  1012 ML%linenosgray{*let
  1014 ML%linenosgray{*let
  1013   fun prove_prop str ctxt =
  1015   fun prove_prop str lthy =
  1014     let
  1016     let
  1015       val prop = Syntax.read_prop ctxt str
  1017       val prop = Syntax.read_prop lthy str
  1016     in
  1018     in
  1017       Proof.theorem_i NONE (K I) [[(prop,[])]] ctxt
  1019       Proof.theorem_i NONE (K I) [[(prop,[])]] lthy
  1018     end;
  1020     end;
  1019   
  1021   
  1020   val prove_prop_parser = OuterParse.prop >> prove_prop 
  1022   val prove_prop_parser = OuterParse.prop >> prove_prop 
  1021   val kind = OuterKeyword.thy_goal
  1023   val kind = OuterKeyword.thy_goal
  1022 in
  1024 in
  1050   \isacommand{apply}@{text "(rule conjI)"}\\
  1052   \isacommand{apply}@{text "(rule conjI)"}\\
  1051   \isacommand{apply}@{text "(rule TrueI)+"}\\
  1053   \isacommand{apply}@{text "(rule TrueI)+"}\\
  1052   \isacommand{done}
  1054   \isacommand{done}
  1053   \end{isabelle}
  1055   \end{isabelle}
  1054 
  1056 
  1055   (FIXME: read a name and show how to store theorems)
  1057   (FIXME: read a name and show how to store theorems; see @{ML LocalTheory.note})
       
  1058   
  1056 *}
  1059 *}
  1057 
  1060 
  1058 section {* Methods (TBD) *}
  1061 section {* Methods (TBD) *}
  1059 
  1062 
  1060 text {*
  1063 text {*
  1073   \end{isabelle}
  1076   \end{isabelle}
  1074 
  1077 
  1075   An example of a very simple method is:
  1078   An example of a very simple method is:
  1076 *}
  1079 *}
  1077 
  1080 
  1078 method_setup %gray foobar_meth = 
  1081 method_setup %gray foobar = 
  1079  {* Scan.succeed
  1082  {* Scan.succeed
  1080       (K (SIMPLE_METHOD ((etac @{thm conjE} THEN' rtac @{thm conjI}) 1))) *}
  1083       (K (SIMPLE_METHOD ((etac @{thm conjE} THEN' rtac @{thm conjI}) 1))) *}
  1081          "foobar method for conjE and conjI"
  1084          "foobar method for conjE and conjI"
  1082 
  1085 
  1083 text {*
  1086 text {*
  1084   It defines the method @{text foobar_meth}, which takes no arguments (therefore the
  1087   It defines the method @{text foobar}, which takes no arguments (therefore the
  1085   parser @{ML Scan.succeed}) and only applies a single tactic, namely the tactic which 
  1088   parser @{ML Scan.succeed}) and only applies a single tactic, namely the tactic which 
  1086   applies @{thm [source] conjE} and then @{thm [source] conjI}. The function @{ML SIMPLE_METHOD}
  1089   applies @{thm [source] conjE} and then @{thm [source] conjI}. The function @{ML SIMPLE_METHOD}
  1087   turns such a tactic into a method. @{text "Foobar_meth"} can be used as follows
  1090   turns such a tactic into a method. The method @{text "foobar"} can be used as follows
  1088 *}
  1091 *}
  1089 
  1092 
  1090 lemma shows "A \<and> B \<Longrightarrow> C \<and> D"
  1093 lemma shows "A \<and> B \<Longrightarrow> C \<and> D"
  1091 apply(foobar_meth)
  1094 apply(foobar)
  1092 txt {*
  1095 txt {*
  1093   where it results in the goal state
  1096   where it results in the goal state
  1094 
  1097 
  1095   \begin{minipage}{\textwidth}
  1098   \begin{minipage}{\textwidth}
  1096   @{subgoals}
  1099   @{subgoals}