(* Title: Standard Basis Library: Word8 Structure Author: David Matthews Copyright David Matthews 1999 This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *) (* G&R 2004 status: checked, no change *) structure Word8 :> WORD = struct (* This structure is largely derived from Word but we use opaque signature matching so that it is a different type. *) open Word (* Values of type Word8.word can be in the range 0..255 and are implemented using tagged integers. *) (* There seem to be two ways to implement this, given that the underlying representation is a tagged 30/31 bit integer. We could either ensure that the top 22/23 bits are always zero and mask them after every operation (or if the code-generator was clever, after several) or we could allow these bits to be undefined and mask them before any operation which could expose them. For the moment we choose the former. *) (* N.B. The Byte structure contains functions which map between Word8.word values and Char.char. It assumes that the underlying representation is the same. *) val wordSize = 8 val maxWord = 255 val maxWordAsWord: word = RunCall.unsafeCast maxWord infix 8 << >> ~>> (* Comparison operations, min, max and compare, fmt, toString, orb, andb, xorb can be inherited directly from Word. Similarly div and mod since the results will always be no larger than the arguments. *) (* Not the same as Word.notb because it only affects the bottom 8 bits. *) fun notb x = xorb(maxWordAsWord, x) (* Internal function to convert from Word.word. *) fun fromWord (w: Word.word) = andb(w, maxWordAsWord) (* Converting from LargeWord.word. First convert to Word.word and then mask. *) val fromLargeWord = fromWord o Word.fromLargeWord and fromInt = fromWord o Word.fromInt and fromLargeInt = fromWord o Word.fromLargeInt val fromLarge = fromLargeWord (* Arithmetic shift - sign extends. *) (* TODO: Replace by built-in? We need a separate function from arithmetic shift for Word because the sign bit is in a different place. *) (* Shift the "sign" bit into the real sign bit position then shift right down again. *) local val toSignBit = Word.fromInt(Int.-(Word.wordSize,wordSize)) in fun op ~>> (a: word, b: Word.word): word = fromWord(Word.~>>(Word.<<(a, toSignBit), Word.+(b, toSignBit))) end (* TODO: Replace with built-in? We need to mask the result so that it remains in the range 0..255 *) fun op << (a: word, b: Word.word): word = andb(Word.<<(a,b), maxWordAsWord) (* Conversion to unsigned integer. This is simpler than for Word because all Word8 values correspond to short integers. *) val toInt: word->int = RunCall.unsafeCast (* Conversion to signed integer. *) (* TODO: This could be implemented using shifts. i.e logical shift left by (Word.wordSize-Word8.wordSize) then arithmetic shift right by the same amount. *) fun toIntX (x: word) : int = let val intx = toInt x open Int (* We want integer arithmetic here. *) in if intx >= 128 then intx-maxWord-1 else intx end val toLargeInt = LargeInt.fromInt o toInt and toLargeIntX = LargeInt.fromInt o toIntX (* Convert to a large word by sign extending. *) fun toLargeWordX (w: word): LargeWord.word = LargeWord.fromInt(toIntX w); val toLargeX = toLargeWordX (* Use Word.scan but check that the result is in the range. *) val wordScan = scan; fun scan radix getc src = case wordScan radix getc src of NONE => NONE | SOME(res, src') => if res > maxWordAsWord then raise General.Overflow else SOME(res, src') val fromString = StringCvt.scanString (scan StringCvt.HEX) (* TODO: Replace by built-ins? *) fun op + (a, b) = fromWord(Word.+(a, b)) and op - (a, b) = fromWord(Word.-(a, b)) and op * (a, b) = fromWord(Word.*(a, b)) fun ~ x = 0w0 - x end; (* Because we are using opaque signature matching we have to install type-dependent functions OUTSIDE the structure. *) local (* The string may be either 0wnnn or 0wxXXX *) fun convWord s : Word8.word = let val radix = (* The word value must consist of at least 0w and a digit. *) if String.sub(s, 2) = #"x" then StringCvt.HEX else StringCvt.DEC in case StringCvt.scanString (Word8.scan radix) s of NONE => raise RunCall.Conversion "Invalid word8 constant" | SOME res => res end (* Install the pretty printer for Word8.word *) fun pretty _ _ x = PolyML.PrettyString("0wx" ^ Word8.toString x) in val () = RunCall.addOverload convWord "convWord" val () = PolyML.addPrettyPrinter pretty end; (* Add the overloaded operators. *) val () = RunCall.addOverload Word8.~ "~"; val () = RunCall.addOverload Word8.+ "+"; val () = RunCall.addOverload Word8.- "-"; val () = RunCall.addOverload Word8.* "*"; val () = RunCall.addOverload Word8.div "div"; val () = RunCall.addOverload Word8.mod "mod"; val () = RunCall.addOverload Word8.< "<"; val () = RunCall.addOverload Word8.> ">"; val () = RunCall.addOverload Word8.<= "<="; val () = RunCall.addOverload Word8.>= ">=";