Nominal/activities/tphols09/IDW/SB-Calc.thy
author Christian Urban <christian dot urban at kcl dot ac dot uk>
Wed, 30 Mar 2016 17:27:34 +0100
changeset 415 f1be8028a4a9
permissions -rw-r--r--
updated
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
415
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
     1
theory Calc
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
     2
imports Main
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
     3
begin
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
     4
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
     5
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
     6
section {* A Simple Calculator *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
     7
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
     8
text {*
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
     9
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    10
Task: Write a calculator which behaves as follows:
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    11
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    12
  calc "ADD 1 2"   = 3
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    13
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    14
  calc "SUM 1 2 3"   = 6
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    15
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    16
  cal "LET x 3 IN ADD x 1"   = 4
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    17
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    18
*}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    19
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    20
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    21
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    22
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    23
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    24
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    25
subsection {* A Parser Primer *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    26
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    27
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    28
(*  'a -> 'b  *)
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    29
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    30
(*  'a -> 'b * 'c  *)
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    31
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    32
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    33
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    34
(*  string list -> 'a * string list  *)
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    35
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    36
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    37
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    38
(*  FAIL  *)
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    39
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    40
(*  MORE  *)
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    41
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    42
(*  ABORT *)
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    43
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    44
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    45
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    46
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    47
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    48
subsection {* Lexer: From a String to a Token List *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    49
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    50
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    51
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    52
ML {*
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    53
datatype token =
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    54
  Keyword of string |
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    55
  Number of int |
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    56
  Variable of string |
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    57
  Space |
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    58
  End
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    59
*}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    60
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    61
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    62
ML {* Scan.many1 *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    63
ML {*
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    64
val keyword = Scan.many1 Symbol.is_ascii_upper
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    65
*}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    66
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    67
ML {* keyword (explode "AND 1 2") *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    68
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    69
ML {* try keyword (explode "AND") *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    70
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    71
ML {* try keyword (explode " AND") *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    72
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    73
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    74
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    75
ML {*
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    76
val keyword = Scan.many1 Symbol.is_ascii_upper >>
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    77
  (Keyword o implode)
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    78
*}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    79
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    80
ML {* op >> *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    81
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    82
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    83
ML {* keyword (explode "AND 1 2") *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    84
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    85
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    86
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    87
ML {*
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    88
val variable = Scan.many1 Symbol.is_ascii_lower >>
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    89
  (Variable o implode)
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    90
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    91
val space = Scan.many1 Symbol.is_ascii_blank >> K Space
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    92
*}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    93
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    94
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    95
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    96
ML {*
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    97
fun int_of d = ord d - ord "0"
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    98
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
    99
fun join_digits ds =
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   100
  fold (fn d => fn i => 10 * i + int_of d) ds 0
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   101
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   102
val number = Scan.many1 Symbol.is_ascii_digit >>
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   103
  (Number o join_digits)
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   104
*}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   105
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   106
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   107
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   108
ML {*
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   109
val tokens = Scan.bulk
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   110
  (keyword || variable || number || space)
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   111
*}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   112
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   113
ML {* op || *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   114
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   115
ML {* Scan.bulk *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   116
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   117
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   118
ML {* tokens (explode "ADD 1 2") *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   119
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   120
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   121
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   122
ML {*
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   123
fun lex str =
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   124
  explode str
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   125
  |> these o Scan.read Symbol.stopper tokens
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   126
  |> filter_out (fn Space => true | _ => false)
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   127
*}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   128
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   129
ML {* Scan.read *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   130
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   131
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   132
ML {* lex "ADD 1 2" *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   133
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   134
ML {* lex "SUM 1 2 3" *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   135
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   136
ML {* lex "LET x 3 IN ADD x 1" *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   137
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   138
ML {* lex "ADD 1 (ADD 2 3)" *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   139
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   140
ML {* tokens (explode "ADD (ADD 1 2) 3") *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   141
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   142
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   143
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   144
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   145
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   146
subsection {* Lexer: Error Handling *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   147
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   148
ML {* Scan.!! *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   149
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   150
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   151
ML {*
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   152
val token = keyword || variable || number || space
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   153
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   154
fun bad_input s = "Unexpected symbol: " ^ quote s
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   155
fun lex_err (xs, _) = bad_input (hd xs)
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   156
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   157
val tokens = Scan.!! lex_err (Scan.bulk token)
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   158
*}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   159
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   160
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   161
ML {* tokens (explode "ADD (ADD 1 2) 3") *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   162
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   163
ML {*
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   164
let
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   165
  fun lex1 str =
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   166
    explode str
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   167
    |> Scan.read Symbol.stopper tokens
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   168
in
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   169
  lex1 "ADD (ADD 1 2) 3"
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   170
end
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   171
*}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   172
ML {*
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   173
let
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   174
  fun lex2 str =
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   175
    explode str
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   176
    |> tokens
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   177
in
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   178
  lex2 "ADD 1 2"
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   179
end
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   180
*}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   181
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   182
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   183
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   184
ML {*
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   185
fun lex str =
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   186
  Source.of_string str
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   187
  |> Source.source Symbol.stopper tokens NONE
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   188
  |> Source.exhaust
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   189
  |> filter_out (fn Space => true | _ => false)
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   190
*}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   191
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   192
ML {* lex "ADD 1 2" *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   193
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   194
ML {* lex "SUM 1 2 3" *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   195
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   196
ML {* lex "LET x 3 IN ADD x 1" *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   197
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   198
ML {* try lex "ADD 1 (ADD 2 3" *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   199
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   200
ML {* lex "Add 1 2" *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   201
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   202
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   203
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   204
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   205
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   206
subsection {* Calculator: Basic Expressions *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   207
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   208
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   209
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   210
ML {*
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   211
fun keyword name = Scan.one
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   212
  (fn Keyword n => n = name | _ => false)
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   213
*}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   214
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   215
ML {*
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   216
val number = Scan.some
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   217
  (fn Number n => SOME n | _ => NONE)
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   218
*}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   219
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   220
ML {*
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   221
val stop = Scan.one (fn t => t = End)
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   222
*}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   223
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   224
ML {*
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   225
fun expr st =
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   226
 (number ||
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   227
  keyword "ADD" |-- expr -- expr >> (op +) ||
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   228
  keyword "SUM" |-- 
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   229
    Scan.unless stop (Scan.repeat expr) >>
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   230
      (fn is => fold (curry (op +)) is 0)) st
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   231
*}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   232
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   233
ML {*
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   234
val f1 = op  --
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   235
val f2 = op |--
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   236
val f3 = op  --|
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   237
*}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   238
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   239
ML {* expr (lex "ADD 1 2" @ [End]) *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   240
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   241
ML {* expr (lex "SUM 1 2 3" @ [End]) *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   242
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   243
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   244
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   245
ML {*
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   246
fun calc str = 
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   247
  lex str @ [End]
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   248
  |> expr --| stop
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   249
  |> fst
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   250
*}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   251
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   252
ML {* calc "ADD 1 2" *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   253
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   254
ML {* calc "SUM 1 2 3" *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   255
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   256
ML {* calc "ADD 1 ADD 2 3" *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   257
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   258
ML {* calc "ADD 1 SUM 2 3 4" *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   259
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   260
ML {* calc "SUM ADD 1 2 3" *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   261
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   262
ML {* try calc "ADD SUM 1 2 3" *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   263
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   264
ML {* try calc "ADD 1 2 3" *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   265
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   266
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   267
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   268
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   269
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   270
subsection {* Calculator: Error Handling *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   271
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   272
ML {*
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   273
fun string_of_token (Keyword s) = s
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   274
  | string_of_token (Variable s) = s
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   275
  | string_of_token (Number n) = string_of_int n
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   276
  | string_of_token _ = "end"
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   277
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   278
fun bad_token (xs, _) =
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   279
  "Unexpected token: " ^ quote (string_of_token (hd xs))
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   280
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   281
fun calc str =
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   282
  lex str @ [End]
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   283
  |> Scan.error (expr --| Scan.!! bad_token stop)
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   284
  |> fst
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   285
*}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   286
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   287
ML {* try calc "ADD 1 2 3" *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   288
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   289
ML {* try calc "ADD SUM 1 2 3" *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   290
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   291
ML {* try calc "Add 0 0" *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   292
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   293
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   294
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   295
ML {*
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   296
fun append_token msg xs =
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   297
  msg ^ quote (string_of_token (hd xs))
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   298
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   299
val expr' =
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   300
  expr ||
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   301
  Scan.fail_with (append_token ("Expected number, " ^
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   302
    "ADD, or SUM, instead of "))
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   303
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   304
val stop' =
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   305
  stop ||
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   306
  Scan.fail_with (append_token "Unexpected token ")
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   307
*}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   308
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   309
ML {*
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   310
fun calc str =
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   311
  lex str @ [End]
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   312
  |> Scan.catch (expr' --| stop')
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   313
  |> fst
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   314
*}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   315
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   316
ML {* try calc "ADD 0 0 1" *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   317
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   318
ML {* try calc "Add 0 0" *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   319
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   320
ML {* try calc "ADD SUM 1 2 3" *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   321
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   322
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   323
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   324
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   325
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   326
subsection {* Calculator: Expressions with Variables *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   327
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   328
ML {*
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   329
fun keyword name = Scan.lift (Scan.one
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   330
  (fn Keyword n => n = name | _ => false))
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   331
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   332
fun number st = Scan.lift (Scan.some
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   333
  (fn Number n => SOME n | _ => NONE)) st
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   334
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   335
fun stop st = Scan.lift (Scan.one 
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   336
  (fn t => t = End orelse t = Keyword "IN")) st
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   337
*}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   338
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   339
ML {* Scan.lift *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   340
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   341
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   342
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   343
ML {*
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   344
val variable = Scan.some
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   345
  (fn Variable n => SOME n | _ => NONE)
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   346
*}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   347
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   348
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   349
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   350
ML {*
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   351
fun lookup env v =
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   352
  (case Symtab.lookup env v of
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   353
    SOME i => i
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   354
  | _ => error ("Unbound variable " ^ quote v))
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   355
*}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   356
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   357
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   358
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   359
ML {*
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   360
fun expr st =
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   361
 (number ||
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   362
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   363
  Scan.peek (fn env => variable >> lookup env) ||
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   364
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   365
  keyword "LET" |-- Scan.lift variable -- expr --|
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   366
    keyword "IN" :|--
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   367
      (fn b => apfst (Symtab.update b) #> expr) ||
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   368
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   369
  keyword "ADD" |-- expr -- expr >> (op +) ||
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   370
  keyword "SUM" |-- 
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   371
    Scan.unless stop (Scan.repeat expr) >>
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   372
      (fn is => fold (curry (op +)) is 0)) st
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   373
*}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   374
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   375
ML {* Scan.peek *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   376
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   377
ML {* op :|-- *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   378
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   379
ML {* expr (Symtab.empty, lex "LET x 1 IN x") *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   380
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   381
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   382
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   383
ML {*
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   384
fun calc str =
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   385
  lex str @ [End]
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   386
  |> Scan.pass Symtab.empty (expr --| stop)
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   387
  |> fst
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   388
*}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   389
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   390
ML {* calc "ADD 1 2" *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   391
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   392
ML {* calc "ADD 1 ADD 2 3" *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   393
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   394
ML {* calc "SUM 1 2 3" *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   395
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   396
ML {* calc "LET x 3 IN ADD x 1" *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   397
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   398
ML {* calc "LET x SUM 1 1 1 IN ADD x 7" *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   399
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   400
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   401
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   402
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   403
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   404
subsection {* Possible extensions *}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   405
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   406
text {*
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   407
Errors with source positions:
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   408
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   409
  see Pure/General/source_pos.ML
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   410
*}
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   411
f1be8028a4a9 updated
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff changeset
   412
end