1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
|
(***********************************************************************)
(* *)
(* Objective Caml *)
(* *)
(* Pierre Weis, projet Cristal, INRIA Rocquencourt *)
(* *)
(* Copyright 2001 Institut National de Recherche en Informatique et *)
(* en Automatique. All rights reserved. This file is distributed *)
(* only by permission. *)
(* *)
(***********************************************************************)
(*
- Variables exist in Caml.
A variable x is defined using the ``ref'' variable constructor
applied to its initial value (initial value is mandatory).
let x = ref 0
The variable can be modified using the assignment operator :=
x := 3
*)
let chars = ref 0
and words = ref 0
and lines = ref 0
;;
(*
- New type definitions are introduced by the keyword type. To define an
enumerated type, just list the set of alternatives.
Here type state introduced two cases, Inside_word and Outside_word,
that will serve3 to denote if we are scanning a word or not.
*)
type state = Inside_word | Outside_word;;
(*
- Case analysis is introduced by match. It is a list of clauses
| pat -> e
meaning that if pat is the case at hand, e should be returned.
For instance, to return integer 1 if character c is 'a' and 2 if c
is 'b', use
match c with
| 'a' -> 1
| 'b' -> 2
A catch all case is introduced by special pattern ``_''. Hence,
match c with
| 'a' -> true
| _ -> false
tests is character c is 'a'.
- Character can be read in input channel using primitive input_char.
- Primitive incr, increments a variable.
*)
let count_channel in_channel =
let rec count status =
let c = input_char in_channel in
incr chars;
match c with
| '\n' ->
incr lines; count Outside_word
| ' ' | '\t' ->
count Outside_word
| _ ->
if status = Outside_word then incr words;
count Inside_word in
try
count Outside_word
with End_of_file -> ()
;;
(*
- Primitive open_in opens an input channel.
*)
let count_file name =
let ic = open_in name in
count_channel ic;
close_in ic
;;
(*
- The current value of variable x is denoted by !x.
Hence incr x is equivalent to x := !x + 1
*)
let print_result () =
print_int !chars; print_string " characters, ";
print_int !words; print_string " words, ";
print_int !lines; print_string " lines";
print_newline ()
;;
let count name =
count_file name;
print_result ()
;;
if !Sys.interactive then () else
try
if Array.length Sys.argv <= 1 then
count_channel stdin (* No command-line arguments *)
else
for i = 1 to Array.length Sys.argv - 1 do
count_file Sys.argv.(i)
done;
print_result ();
with Sys_error s ->
print_string "I/O error: ";
print_string s;
print_newline ()
;;
|