1(*
2    Title:      Standard Basis Library: Word8 Structure
3    Author:     David Matthews
4    Copyright   David Matthews 1999
5
6    This library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10    
11    This library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15    
16    You should have received a copy of the GNU Lesser General Public
17    License along with this library; if not, write to the Free Software
18    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19*)
20
21(* G&R 2004 status: checked, no change *)
22
23structure Word8 :> WORD =
24struct
25    (* This structure is largely derived from Word but we use opaque
26       signature matching so that it is a different type. *)
27    open Word
28    
29    (* Values of type Word8.word can be in the range 0..255 and
30       are implemented using tagged integers.  *)
31    (* There seem to be two ways to implement this, given that the underlying
32       representation is a tagged 30/31 bit integer.  We could either ensure
33       that the top 22/23 bits are always zero and mask them after every
34       operation (or if the code-generator was clever, after several) or 
35       we could allow these bits to be undefined and mask them before any
36       operation which could expose them.  For the moment we choose the
37       former.  *)
38    (* N.B. The Byte structure contains functions which map between
39       Word8.word values and Char.char.  It assumes that the underlying
40       representation is the same. *)
41
42    val wordSize = 8
43    val maxWord = 255
44    val maxWordAsWord: word = RunCall.unsafeCast maxWord
45    
46    infix 8 << >> ~>>
47
48    (* Comparison operations, min, max and compare, fmt, toString,
49       orb, andb, xorb can be inherited directly from Word.
50       Similarly div and mod since the results will always be no
51       larger than the arguments. *)
52
53    (* Not the same as Word.notb because it only affects the bottom 8 bits.  *)
54    fun notb x = xorb(maxWordAsWord, x)
55
56    (* Internal function to convert from Word.word. *)
57    fun fromWord (w: Word.word) = andb(w, maxWordAsWord)
58
59    (* Converting from LargeWord.word.  First convert to Word.word and
60       then mask. *)
61    val fromLargeWord = fromWord o Word.fromLargeWord
62    and fromInt = fromWord o Word.fromInt
63    and fromLargeInt = fromWord o Word.fromLargeInt
64    
65    val fromLarge = fromLargeWord
66
67            (* Arithmetic shift - sign extends. *)
68    (* TODO: Replace by built-in?  We need a separate function from
69       arithmetic shift for Word because the sign bit is in a different
70       place.  *)
71    (* Shift the "sign" bit into the real sign bit position then
72       shift right down again. *)
73    local
74        val toSignBit = Word.fromInt(Int.-(Word.wordSize,wordSize))
75    in
76        fun op ~>> (a: word, b: Word.word): word =
77            fromWord(Word.~>>(Word.<<(a, toSignBit), Word.+(b, toSignBit)))
78    end
79    
80    (* TODO: Replace with built-in?  We need to mask the result so
81       that it remains in the range 0..255 *)
82    fun op << (a: word, b: Word.word): word = andb(Word.<<(a,b), maxWordAsWord)
83
84    (* Conversion to unsigned integer.  This is simpler than for Word
85       because all Word8 values correspond to short integers. *)
86    val toInt: word->int = RunCall.unsafeCast
87    
88    (* Conversion to signed integer. *)
89    (* TODO: This could be implemented using shifts. i.e logical shift
90       left by (Word.wordSize-Word8.wordSize) then arithmetic shift
91       right by the same amount. *)
92    fun toIntX (x: word) : int =
93        let
94            val intx = toInt x
95            open Int (* We want integer arithmetic here. *)
96        in
97            if intx >= 128
98            then intx-maxWord-1
99            else intx
100        end
101    
102    val toLargeInt = LargeInt.fromInt o toInt
103    and toLargeIntX = LargeInt.fromInt o toIntX
104
105    (* Convert to a large word by sign extending. *)
106    fun toLargeWordX (w: word): LargeWord.word =
107        LargeWord.fromInt(toIntX w);
108    val toLargeX = toLargeWordX
109    
110    (* Use Word.scan but check that the result is in the range. *)
111    val wordScan = scan;
112
113    fun scan radix getc src =
114        case wordScan radix getc src of
115            NONE => NONE
116         |  SOME(res, src') =>
117                if res > maxWordAsWord
118                then raise General.Overflow
119                else SOME(res, src')
120
121    val fromString = StringCvt.scanString (scan StringCvt.HEX)
122
123    (* TODO: Replace by built-ins? *)
124    fun op + (a, b) = fromWord(Word.+(a, b))
125    and op - (a, b) = fromWord(Word.-(a, b))
126    and op * (a, b) = fromWord(Word.*(a, b))
127    
128    fun ~ x = 0w0 - x
129
130end;
131
132(* Because we are using opaque signature matching we have to install
133   type-dependent functions OUTSIDE the structure. *)
134local
135    (* The string may be either 0wnnn or 0wxXXX *)
136    fun convWord s : Word8.word =
137        let
138        val radix =
139            (* The word value must consist of at least 0w and a digit. *)
140            if String.sub(s, 2) = #"x" then StringCvt.HEX else StringCvt.DEC
141        in
142            case StringCvt.scanString (Word8.scan radix) s of
143                NONE => raise RunCall.Conversion "Invalid word8 constant"
144              | SOME res => res
145        end
146        
147    (* Install the pretty printer for Word8.word *)
148    fun pretty _ _ x = PolyML.PrettyString("0wx" ^ Word8.toString x)
149in
150    val () = RunCall.addOverload convWord "convWord"
151    val () = PolyML.addPrettyPrinter pretty
152end;
153
154(* Add the overloaded operators. *)
155val () = RunCall.addOverload Word8.~ "~";
156val () = RunCall.addOverload Word8.+ "+";
157val () = RunCall.addOverload Word8.- "-";
158val () = RunCall.addOverload Word8.* "*";
159val () = RunCall.addOverload Word8.div "div";
160val () = RunCall.addOverload Word8.mod "mod";
161val () = RunCall.addOverload Word8.< "<";
162val () = RunCall.addOverload Word8.> ">";
163val () = RunCall.addOverload Word8.<= "<=";
164val () = RunCall.addOverload Word8.>= ">=";
165