// stdlib - generic subroutines for ILOC
//
// This library contains a few common subroutines for Boppi.
//
// @author Frank Wibbelink

// initialise
stdlib_: jumpI -> estdlib_

// write a boolean to output
// stack: [return address, bool] -> []
stdbout: pop => m_1                 // get boolean
         loadI 0 => m_2             // load zero-length string
         push m_2
         cbr m_1 -> sbout_t,sbout_f
sbout_t: cout "true"
         jumpI -> sbout_e
sbout_f: cout "false"
sbout_e: pop => m_1                 // load return address
         jump -> m_1


// write an array of characters (a string) to output
// stack: [return address, address] -> []
stdsout: pop => m_1                   // get address
         loadAI m_1,@off_osize => m_2 // get length
sout_lc: cbr m_2 -> sout_ll,sout_le   // check if any character to push
sout_ll: subI m_2, 1 => m_2           // iterate backward
         cloadAO m_1, m_2 => m_c      // get character
         cpush m_c                    // push character
         jumpI -> sout_lc             // repeat
sout_le: loadAI m_1,@off_osize => m_2 // get length
         push m_2                     // push string length
         cout ""                      // print string
         pop => m_1                   // get return address
         jump -> m_1


// read a character from input
// stack: [return address] -> [char]
stdcin:  cin ""                     // get line
         pop => m_1                 // get length
         cbr m_1 -> scin_t,stdcin   // repeat until at least one character
scin_t:  cpop => m_2                // save character
scin_lc: subI m_1, 1 => m_1         // decrement char count
         cbr m_1 -> scin_ll,scin_le
scin_ll: cpop => m_0                // discard character
         jumpI -> scin_lc           // repeat
scin_le: loadI 0 => m_0             // reset zero register
         pop => m_1                 // get return address
         cpush m_2                  // push result character
         jump -> m_1


// read an array of characters (a string) from input
// the memalloc label cannot be used, so address 28 is used instead
// stack: [return address] -> [address]
stdsin:  cin ""                     // get line
         pop => m_2                 // get length
         push m_2                   // save length
         loadI #ssin_a => m_1       // call malloc
         push m_1                   // call malloc
         push m_2                   // call malloc
         loadI 28 => m_c            // call malloc
         jump -> m_c                // call malloc
ssin_a:  pop => m_1                 // get array address
         pop => m_2                 // get length
         i2i m_1 => m_n             // load character iterator
ssin_c:  cbr m_2 -> ssin_l, ssin_e  // pop characters into the array
ssin_l:  subI m_2,1 => m_2
         cpop => m_c                // pop character
         cstore m_c => m_n          // save character
         addI m_n,1 => m_n          // increment iterator
         jumpI -> ssin_c
ssin_e:  pop => m_2                 // get return address
         push m_1                   // push array address
         jump -> m_2



estdlib_: nop
// end of stdlib