This is poke.info, produced by makeinfo version 6.7 from poke.texi.

This manual describes GNU poke (version 3.3, 20 August 2023).

   Copyright (C) 2019, 2020, 2021, 2022, 2023 The poke authors.

     You can redistribute it and/or modify this manual under the terms
     of the GNU General Public License as published by the Free Software
     Foundation, either version 3 of the License, or (at your option)
     any later version.
INFO-DIR-SECTION Editors
START-INFO-DIR-ENTRY
* poke: (poke). Interactive editor for binary files.
END-INFO-DIR-ENTRY


File: poke.info,  Node: Presentation options for dump,  Prev: Information dump shows,  Up: dump

19.1.2 Presentation options for 'dump'
--------------------------------------

By default, the hexadecimal display shows two bytes grouped together,
and then a space.  You can alter this behaviour using the 'group_by'
parameter.

     (poke) dump :ascii 0 :size 0x40#B :group_by 4#B
     00000000: 68f19a63 df2a8886 c466631c a7fdd5c7  h..c.*...fc.....
     00000010: 3075746a 0adb03ca f5b1ff14 6166fa07  0utj........af..
     00000020: 0dd3cfbd 8eff46a2 4152a81d 471beddf  ......F.AR..G...
     00000030: a0501cae 8bfcec6f 7a4f5701 45ba9fc3  .P.....ozOW.E...

   Another parameter is the 'cluster_by' argument.  By setting
'cluster_by' to N, this causes 'dump' to display an additional space
after the Nth group has been displayed, and also in the corresponding
position in the ascii display:

     (poke) dump :size 0x40#B :group_by 2#B :cluster_by 4
     76543210  0011 2233 4455 6677  8899 aabb ccdd eeff  01234567 89ABCDEF
     00000000: 91b8 540d d4dc 49ae  3320 ba7d efd1 16ab  ..T...I. 3 .}....
     00000010: b1a8 5ea0 5846 8bea  f741 3f80 42bc 201f  ..^.XF.. .A?.B. .
     00000020: 6e5e fa50 23fb f16a  d380 be8c fc98 d195  n^.P#..j ........
     00000030: 7bbf fa3e 3fc2 43a4  2a1e 9763 2bd6 5d24  {..>?.C. *..c+.]$

   Another variable that the user can customize is
'pk_dump_nonprintable_char'.  It defaults to ''.'', and contains the
character to use in the ASCII dump to represent a non-printable
character.

   Not all bytes from an IO space can be read, depending on the kind of
IO device.  When 'dump' cannot read a byte it will print
'pk_dump_unknown_byte' instead, which is a string.

   If the variable 'pk_dump_addr_hyperlinks' is 1 then the 'dump'
command will emit hyperlinks in the printed bytes.  Clicking on a byte
value will result on the address of that byte to be inserted at the
prompt.

   If you have a personal preference on how memory dumps should appear,
you can set the relevant 'pk_dump_*' variables.  These global variables
serve as the defaults for 'dump', so this way, you will not need to
explicitly pass them when you call the function.


File: poke.info,  Node: copy,  Next: save,  Prev: dump,  Up: Commands

19.2 'copy'
===========

The command 'copy' allows to copy regions of data inside an IO space, or
between different IO spaces.

   This command has the following synopsis.

     copy [:from OFFSET] [:to OFFSET] [:size OFFSET]
          [:from_ios IOS] [:to_ios IOS]

All arguments are optional.  When invoked with no arguments, 'copy' does
nothing.

   The arguments 'from' and 'size' determine the region to copy.  By
default, this region is taken from the current IO space, but this can be
overwritten using the optional 'from_ios' argument.

   The argument 'to' tells 'copy' where to copy the stuff.  It defaults
to 'from'.  Again, this offset is applied to the current IO space by
default, but this can be overwritten using the 'to_ios' argument.

   Note that it is allowed for the source and destination ranges to
overlap.


File: poke.info,  Node: save,  Next: sdiff,  Prev: copy,  Up: Commands

19.3 'save'
===========

Use the 'save' command in order to write a region from an IO space into
a file in your file system.

   This command has the following synopsis.

     save [:ios IOS] [:from OFFSET] [:size OFFSET] [:file STRING]
          [:append BOOL] [:verbose BOOL]

All arguments are optional.  When invoked with no arguments, 'save' does
nothing.

   The arguments 'from' and 'size' are used to determine the region of
the IO space to save.  This is how you would extract and save the
contents of an ELF section to a file 'out.text':

     (poke) var s = elf_section_by_name (Elf64_Ehdr @ 0#B, ".text")
     (poke) save :file "out.text" :from s.sh_offset :size s.sh_size

Both 'from' and 'size' are arbitrary offsets.  You should keep in mind
however that files are byte oriented.  Therefore saving, say, nine bits
to a file will actually write two bytes.

   By default 'save' will extract the data from the "current IO space".
However, it is possible to specify an alternative IOS by using the 'ios'
argument.

   By default 'save' will truncate the output file, if it exists, before
starting writing.  If the argument 'append' is set as true, however, it
will append to the existing contents of the file.  In this case, the
file should exist.


File: poke.info,  Node: sdiff,  Next: extract,  Prev: save,  Up: Commands

19.4 'sdiff'
============

The 'sdiff' command provides structured byte differences between two
mapped values.

   This command has the following synopsis:

     sdiff :a ANY :b ANY [:group_by OFFSET] \
           [:values BOOL]

Where :A and :B are two mapped values of the same type.

   By default, the bytes are shown in the diff separated by white
characters.  You can alter this behaviour using the 'group_by'
parameter.

   If VALUES is true, then include field interpreted values in the diff
output.

   If the two values are not mapped, this command raises 'E_no_map'.  If
the two values are not of the same type, the output will probably not be
meaningful.


File: poke.info,  Node: extract,  Next: scrabble,  Prev: sdiff,  Up: Commands

19.5 'extract'
==============

Use the 'extract' command in order to create a temporary memory IO space
with the contents of a mapped value.

   This command has the following synopsis.

     extract :val VAL [:to IOS_NAME]

Where ':val' is a mapped value, and :TO is the name of the memory IOS to
create (or use).  The contents of VALUE are copied to the beginning of
the memory IOS '*IOS_NAME*'.

   If no :TO argument is specified, or if it is the empty string, then
the 'extract' command will generate a suitable unique name and use it.


File: poke.info,  Node: scrabble,  Prev: extract,  Up: Commands

19.6 'scrabble'
===============

The 'scrabble' command rearranges portions of an IO space based on a
transformation defined by a pair of patterns.

   This command has the following synopsis:

     scrabble [:from OFFSET] [:size OFFSET]
              [:from_pattern STRING] [:to_pattern STRING]
              [:ent_size OFFSET]
              [:from_ios IOS] [:to_ios IOS]

The optional arguments are documented below.

':from OFFSET'
     Beginning of the range in the origin IO space from where to start
     rearranging units.  Defaults to '0#B'.
':size OFFSET'
     Size of the range to scrabble in the origin IO space.  Defaults to
     '0#B'.
':from_pattern STRING'
     String specifying a sequence of units.  Each character is an unit.
     Defaults to '""'.
':to_pattern STRING'
     String specifying the scrabbled units.  Each character is an unit.
     If a character that doesn't appear in the 'from_pattern' is found
     in this string, it is ignored.  Defaults to 'from_pattern'.
':ent_size OFFSET'
     Size of the entities to scrabble around.  Defaults to '1#B'.
':from_ios IOS'
     IO space from where to obtain the data to scrabble.  Defaults to
     the current IO space.
':to_ios IOS'
     The IO space to where write the scrabbled data.  Defaults to
     'from_ios'.


File: poke.info,  Node: The Poke Language,  Next: The Standard Library,  Prev: Commands,  Up: Top

20 The Poke Language
********************

* Menu:

* Integers::			Whole numbers.
* Offsets::			Memory sizes and offsets.
* Strings::			NULL-terminated strings.
* Arrays::			Homogeneous collections.
* Structs::			Heterogeneous collections.
* Types::			Declaring types.
* Assignments::			Changing the value of variables.
* Compound Statements::		Sequences of statements.
* Conditionals::		Conditional statements and expressions.
* Loops::			Statements to iterate on conditions.
* Expression Statements::	Using expressions for their side-effects.
* Functions::			Procedural abstraction.
* Assembler::                   Assembler instructions with Poke operands.
* Endianness::			Byte ordering.
* Mapping::			Accessing IO spaces.
* Exception Handling::		Dealing with exceptional conditions.
* Terminal::	                Dealing with the terminal.
* Printing::			Output in Poke programs.
* Comments::			Documenting Poke programs.
* Modules::			Loading pickles from Poke programs.
* System::                      Accessing the system from within Poke.
* VM::                          Accessing the PVM in Poke programs.
* Debugging::                   Debugging Poke programs.


File: poke.info,  Node: Integers,  Next: Offsets,  Up: The Poke Language

20.1 Integers
=============

Most of the values manipulated in Poke programs are whole numbers, also
typically known as "integers" in computing parlance.  This is because
integers are pervasive in binary formats, often featuring unusual
characteristics in terms of size and/or alignment.  Single bits denoting
flags or packed small integers are good examples of this.  In order to
ease the manipulation of such entities, and unlike most programming
languages, Poke provides integer types of any number of bits and a rich
set of accompanying operators.

* Menu:

* Integer Literals::		Writing integers in different bases.
* Characters::			Another way to write small integers.
* Booleans::			Integers denoting truth values.
* Integer Types::		int<N> and uint<N>.
* Casting Integers::		Converting integers.
* Relational Operators::	Comparing integers.
* Arithmetic Operators::	Operating with integers.
* Bitwise Operators::		Getting and setting integer bits.
* Boolean Operators::		Equality and inequality.
* Integer Attributes::		Accessing properties of integer values.


File: poke.info,  Node: Integer Literals,  Next: Characters,  Up: Integers

20.1.1 Integer Literals
-----------------------

Integers literals can be expressed in several numeration bases.

   _Decimal numbers_ use the usual syntax '[1-9][0-9]*'.  For example,
'2345'.

   _Octal numbers_ are expressed using a prefix '0o' (or '0O') followed
by one or more digits in the range '[0-7]'.  Examples are '0o0', '0o100'
and '0o777'.

   _Hexadecimal numbers_ are expressed using a prefix '0x' (or '0X')
followed by one or more hexadecimal digits in the range '[0-f]'.
Examples are '0x0' and '0xfe00ffff'.  Note that both the 'x' in the
prefix and the letters in the hexadecimal number are case insensitive.
Thus, '0XdeadBEEF' is a valid (but ugly as hell) literal.

   _Binary numbers_ are expressed using a prefix '0b' (or '0B') followed
by one or more binary digits in the range '[0-1]'.  Examples of binary
literals are '0b0' and '0B010'.

   Negative numbers, of any numeration base, are constructed using the
minus operator as explained below.  Therefore the minus symbol '-' in
negative numbers is not part of the literal themselves.

20.1.1.1 The digits separator '_'
.................................

The character '_' can appear anywhere in a numeric literal except as the
first character.  It is ignored, and its purpose is to make it easier
for programmers to read them:

     0xf000_0000_0000_0000
     0b0000_0001_0000_0001

20.1.1.2 Types of integer literals
..................................

The type of a numeric literal is the smallest signed integer capable of
holding it, starting with 32 bits, in steps of powers of two and up to
64 bits.(1)

   So, for example, the value '2' has type 'int<32>', but the value
'0xffff_ffff' has type 'int<64>', because it is out of the range of
signed 32-bit numbers.

   A set of suffixes can be used to construct integer literals of
certain types explicitly.  'L' or 'l' is for 64-bit integers.  'H' or
'h' is for 16-bit integers (also known as "halves"), 'B' or 'b' is for
8-bit integers (also known as "bytes") and 'n' or 'N' is for 4-bit
integers (also known as "nibbles").

   Thus, '10L' is a 64-bit integer with value '0x0000_0000_0000_000A',
'10H' is a 16-bit integer with value '0x000A' and '10b' is a 8-bit
integer with value '0x0A'.

   Similarly, the signed or unsigned attribute of an integer can be
explicitly specified using the suffix 'u' or 'U' (the default are signed
types).  For example '0xffff_ffffU' has type 'uint<32>' and '0ub' has
type 'uint<8>'.  It is possible to combine width-indicating suffixes
with signedness suffixes: '10UL' denotes the same literal as '10LU'.

   The above rules guarantee that it is always possible to determine the
width and signedness of an integer constant just by looking at it, with
no ambiguity.

   ---------- Footnotes ----------

   (1) Rationale: the width of a C "int" is 32 bits in most currently
used architectures, and binary data formats are usually modelled after
C.


File: poke.info,  Node: Characters,  Next: Booleans,  Prev: Integer Literals,  Up: Integers

20.1.2 Characters
-----------------

8-bit unsigned integers can use an alternative literal notation that is
useful when working with _ASCII character codes_.  Printable character
codes can be denoted with ''c''.

   Non-printable characters can be expressed using escape-sequences.
The allowed sequences are:

'\n'
     New-line character (ASCII 012).
'\t'
     Tab character (ASCII 011).
'\\'
     The backslash character.
'\[0-9][0-9]?[0-9]?'
     Character whose ASCII code is the specified number, in octal.

   Examples:

     'o'
     '\n'
     '\t'
     '\\'
     '\0'

   The type of a character literal is always 'char', aka 'uint<8>'.


File: poke.info,  Node: Booleans,  Next: Integer Types,  Prev: Characters,  Up: Integers

20.1.3 Booleans
---------------

Like in C, truth values in Poke are encoded using integers.  Zero ('0')
denotes the logical value "false", and any integer other than zero
denotes the logical value "true".


File: poke.info,  Node: Integer Types,  Next: Casting Integers,  Prev: Booleans,  Up: Integers

20.1.4 Integer Types
--------------------

Most general-purpose programming languages provide a small set of
integer types, each featuring a range corresponding to strategic storage
sizes: basically, signed and unsigned variants of 8, 16, 32, 64 bits.
As we have seen in the previous sections, suffixes like 'H' or 'L' are
used in Poke for that purpose.

   However, in conventional programming languages when integers having
an "odd" width (like 13 bits, for example) get into play for whatever
reason, the programmer is required to use the integer arithmetic
operators (and sometimes bit-wise operators) herself, in a clever way,
in order to achieve the desired results.

   Poke, on the contrary, provides a rich set of integer types featuring
different widths, in both signed and unsigned variants.  The language
operators are aware of these types, and will do the right thing when
operating on integer values having different widths.

   Unsigned integer types are specified using the type constructor
'uint<N>', where N is the number of bits.  N should be an integer
literal in the range '[1,64]'.  Examples:

     uint<1>
     uint<7>
     uint<64>

   Similarly, signed integer types are created using the type
constructor 'int<N>', where N is the number of bits.  N should be an
integer literal in the range '[1,64]'.  Examples:

     int<1>
     int<8>
     int<64>

   Note that expressions are not allowed in the type integral
constructor parameters.  Not even constant expressions.  Thus, things
like 'int<foo>' and 'uint<2+3>' are not allowed.


File: poke.info,  Node: Casting Integers,  Next: Relational Operators,  Prev: Integer Types,  Up: Integers

20.1.5 Casting Integers
-----------------------

The right-associative unary operator cast 'as' can be used to derive a
new integer value having a different type from an existing value.

   For example, this is how we would create a signed 12-bit integer
value holding the value 666:

     (poke) 666 as int<12>
     (int<12>) 666

   Note that the '666' literal is originally a 32-bit signed integer.
The cast performs the conversion.

   Casts between integer types are always allowed, and never fail.  If
the new type is narrower than the existing type, truncation may be
performed to accommodate the value in its new type.  For example, the
expression '0x8765_4321 as uint<16>' evaluates to '0x4321'.  If the new
type is wider than the existing type, either zero-extension or
sign-extension is performed depending on the signedness of the operand.

   The semantics of the sign-extension operation depends on the
signedness of the value being converted, and on the currently selected
encoding for negative numbers.

   When using two's complement encoding, converting a signed value will
always sign-extend regardless of the signedness of the target type.
Thus:

     (poke) -2H as uint<32>
     0xfffffffeU
     (poke) -2H as int<32>
     0xfffffffe

   Likewise, converting an unsigned value will always zero-extend
regardless of the signedness of the target type.  Thus:

     (poke) 0xffffUH as uint<32>
     0xffffU
     (poke) 0xffffUH as int<32>
     0xffff


File: poke.info,  Node: Relational Operators,  Next: Arithmetic Operators,  Prev: Casting Integers,  Up: Integers

20.1.6 Relational Operators
---------------------------

The following binary relational operators are supported on integer
values, in descending precedence order:

   * Equality '==' and inequality '!='.
   * Less than '<' and less or equal than '<='.
   * Greater than '>' and greater or equal than '>='.

   When applied to integer and character values, these operators
implement an arithmetic ordering.

   These operators resolve in boolean values encoded as 32-bit integers:
'0' meaning false and '1' meaning true.


File: poke.info,  Node: Arithmetic Operators,  Next: Bitwise Operators,  Prev: Relational Operators,  Up: Integers

20.1.7 Arithmetic Operators
---------------------------

The following left-associative binary arithmetic operators are
supported, in descending precedence order:

   * Exponentiation '**', multiplication '*', integer division '/',
     integer ceil-division '/^' and modulus '%'.
   * Addition '+' and subtraction '-'.

   In all the binary arithmetic operations automatic promotions
(coercions) are performed in the operands as needed.  The rules are:

   * If one of the operands is unsigned and the other operand is signed,
     the second is converted to an unsigned value.
   * If the size in bits of one of the operands is bigger than the size
     of the other operand, the second is converted to the same number of
     bits.

   The following right-associative unary arithmetic operators are
supported:

   * Unary minus '-' and unary plus '+'.

   Finally, pre-increment, pre-decrement, post-increment and
post-decrement operators '++' and '--' are supported.


File: poke.info,  Node: Bitwise Operators,  Next: Boolean Operators,  Prev: Arithmetic Operators,  Up: Integers

20.1.8 Bitwise Operators
------------------------

The following left-associative bitwise binary operators are supported,
in descending precedence order:

   * Bitwise shift left '<<.' and bitwise shift right '.>>'.
   * Bitwise AND '&'.
   * Bitwise exclusive OR '^'.
   * Bitwise inclusive OR '|'.
   * Bitwise concatenation ':::'.

   Both '<<.' and '.>>' operators perform logical shifting.  Unlike in
many other programming languages, arithmetic right-shifting operators
are not provided.  This means that right shifting always inserts zeroes
at the most-significant side of the value operand, whereas left shifting
always inserts zeroes at the least-significant side of the value
operand.

   Left shifting by a number of bits equal or bigger than the size of
the value operand is an error, and will trigger either a compile-time
error or a run-time 'E_out_of_bounds' exception.  This does not apply to
right shifting.

   Bitwise concatenation works with any integral type, of any bit
length.

   The following right-associative unary bitwise operators are
supported:

   * Bitwise complement '~'.


File: poke.info,  Node: Boolean Operators,  Next: Integer Attributes,  Prev: Bitwise Operators,  Up: Integers

20.1.9 Boolean Operators
------------------------

The following left-associative, short-circuited binary logical operators
are supported, in descending precedence order:

   * Logical implication: '=>'.
   * Logical AND: '&&'.
   * Inclusive OR: '||'.

   The following right-associative unary logical operators are
supported:

   * Logical negation '!'.


File: poke.info,  Node: Integer Attributes,  Prev: Boolean Operators,  Up: Integers

20.1.10 Integer Attributes
--------------------------

The following attributes are defined for integer values.

'size'
     Gives an offset with the storage occupied by the string.  This
     includes the terminating null.  Examples:

          (poke) 10'size
          0x20UL#b
          (poke) 10N'size
          0x4UL#b
          (poke) (10 as int<1>)'size
          0x1UL#b

'signed'
     Gives 1 if the value is a signed integer, 0 otherwise.  Examples:

          (poke) 10'signed
          1
          (poke) 10UL'signed
          0
'mapped'
     Always 0 for integers.  (*note Mapping::).
'length'
     Always '1UL' for integers.


File: poke.info,  Node: Offsets,  Next: Strings,  Prev: Integers,  Up: The Poke Language

20.2 Offsets
============

Poke uses united values to handle offsets and data sizes.  This is a
very central concept in poke.

* Menu:

* Offset Literals::		Denoting offsets in Poke.
* Offset Units::		Pears and potatoes.
* Offset Types::		offset<...>.
* Casting Offsets::		Converting offsets.
* Offset Operations::		Operating with offsets.
* Offset Attributes::           Accessing properties of offset values.


File: poke.info,  Node: Offset Literals,  Next: Offset Units,  Up: Offsets

20.2.1 Offset Literals
----------------------

Poke provides a convenient syntax to provide united values, which are
called "offsets" (because in a binary editor you mostly use them to
denote offsets in the file you are editing):

     12#B
     7#b
     1024#KB

   The offsets above denote twelve bytes, seven bits and one thousand
twenty four kilobytes, respectively.  The unit can be separated from the
magnitude by blank characters, so you can write the following instead if
you are so inclined:

     12 #B
     7 #b
     (1024 * 1024) #Kb

   Note how the magnitude part of an offset doesn't need to be constant.
If the variable 'a' contains an integer, this is how you would denote "a
bytes":

     a#B

   In the offset syntax units are specified as '#UNIT', where UNIT is
the specification of an unit.  See the next section for details.


File: poke.info,  Node: Offset Units,  Next: Offset Types,  Prev: Offset Literals,  Up: Offsets

20.2.2 Offset Units
-------------------

There are several ways to express the unit of an offset, which is always
interpreted as a multiple of the basic unit, which is the bit (one bit).

20.2.2.1 Named Units
....................

The first way is to refer to an unit by name.  For example, '2#B' for
two bytes.  Units are defined using the 'unit' construction:

     unit NAME = CONSTANT_EXPRESSION [, NAME = CONSTANT_EXPRESSION]...;

where NAME is the name of the unit, and CONSTANT_EXPRESSION is a
constant expression that should evaluate to an integral value.  The
resulting value is always coerced into an unsigned 64-bit integer.

   Note that unit names live in a different namespace than variables and
types.  However, when a given name is both a type name and an unit name
in an unit context, the named unit takes precedence:

     (poke) type xx = int
     (poke) unit xx = 2
     (poke) 1#xx
     1#2

   Many useful units are defined in the standard library.  *Note
Standard Units::.

20.2.2.2 Arbitrary Units
........................

It is also possible to express units in multiples of the base unit,
which is the bit.  Using this syntax, it becomes possible to express
offsets in any arbitrary unit, as disparate as it may seem:

     17#3
     0#12
     8#1

   That's it: 17 units of 3 bits each, zero units of 12 bits each, and
eight units of 1 bit each.  Note that the unit should be greater than 0.

20.2.2.3 Types as Units
.......................

But then, why stop there?  Poking is all about defining data structures
and operating on them... so why not use these structures as units as
well?  Consider the following struct:

     type Packet = struct { int i; long j; };

   The size of a 'Packet' is known at compile time (which is not
generally true for Poke structs).  Wouldn't it be nice to use it as a
unit in offsets?  Sure it is:

     23#Packet

   The above is the size occupied by 23 packets.  Any type whose size is
known at compile time can be specified as an offset unit.

   Expressing offsets as united values also relieves the programmer from
doing many explicit unit conversions: poke can do them for you.
Consider for example an ELF section header.  One of its fields is the
size of the described section, in bytes:

     type Elf64_Shdr =
       struct
       {
        ...
        offset<Elf64_Xword,B> sh_size;
        ...
       };

   If a given section is to contain, say, relocations with addends, we
can set its size doing something like this:

     shdr.sh_size = 10#Elf64_Rela;

Instead of doing the conversion to bytes explicitly.

   If the magnitude of an offset is 1 then it is allowed to omit it
entirely.  To denote one kilobyte, for example, we can write '#KB'.


File: poke.info,  Node: Offset Types,  Next: Casting Offsets,  Prev: Offset Units,  Up: Offsets

20.2.3 Offset Types
-------------------

Offset types are denoted as 'offset<BASE_TYPE,UNIT>', where BASE_TYPE is
an integer type and UNIT the specification of an unit.

   The offset base type is the type of the magnitude part of the united
value.  It can be any integer type, signed or unsigned, of any size.

   The unit specification should be one of the unit identifiers that are
allowed in offset literals (see above), a constant positive integer or
the name of a Poke type whose size is known at compile time.

   Let's see some examples.  A signed 32-bit offset expressed in bytes
has type 'offset<int<32>,B>'.  An unsigned 12-bit offset expressed in
kilobits has type 'offset<uint<12>,Kb>'.  The latter type can also be
written using an explicit integer unit like in 'offset<uint<12>,1024>'.
Finally, a signed 64-bit offset in units of "packets", where a packet is
denoted with a Poke type 'Packet' has type 'offset<uint<64>,Packet>'.


File: poke.info,  Node: Casting Offsets,  Next: Offset Operations,  Prev: Offset Types,  Up: Offsets

20.2.4 Casting Offsets
----------------------

The right-associative unary operator cast 'as' can be used to derive a
new offset value having a different type from an existing value.

   For example, this is how we would create a signed 12-bit offset in
units bytes:

     (poke) 1024#b as offset<int<12>,B>
     (int<12>) 128#B

   The same rules governing conversion of integers apply for the
magnitude part.  Depending on the unit, there can be truncation, like
in:

     (poke) 9#b as offset<int,B>
     1#B


File: poke.info,  Node: Offset Operations,  Next: Offset Attributes,  Prev: Casting Offsets,  Up: Offsets

20.2.5 Offset Operations
------------------------

Poke supports a little algebra for offsets.

20.2.5.1 Addition and subtraction
.................................

The addition or subtraction of two offsets results in another offset.
Examples:

     (poke) 1#B + 1#b
     9#b
     (poke) 2#KB - 1024#B
     1024#B

   The unit of the result is the greatest common divisor of the units of
the operands.

   The operators '++' and '--', in their prefix and suffix versions, can
be applied to offsets as well.  The step used in the increment/decrement
is one unit.

20.2.5.2 Multiplication by a scalar
...................................

Multiplying an offset by a magnitude gives you another offset.
Examples:

     (poke) 8#b * 2
     16#b
     (poke) 16#MB * 0
     0#MB

   The unit of the result is the same as the unit of the offset operand.

   Note that multiplying two offsets is not supported.  This makes
sense, since computer memory is linear, and therefore it wouldn't make
any sense to have units like '#B^{2}'.

20.2.5.3 Division
.................

Dividing two offsets gives you a magnitude.  Examples:

     (poke) 16#b / 1#B
     2
     (poke) 1024#MB / 512#Mb
     16

   Dividing offsets is the Pokish way of converting memory magnitudes
between different units: just use units like you do when doing physics
or working with units in other contexts.

   For example, using the syntactic trick of omitting the magnitude (in
which case it is assumed to be 1) it is very natural to write something
like the following to convert from kilobits to bytes:

     (poke) 24 #Kb/#B
     3072

   There is also a ceil-division operator for offsets, with the same
semantics as the ceil-division for integers:

     (poke) 10#B /^ 3#B
     4

20.2.5.4 Division by an integer
...............................

Dividing an offset by an integer gives you an offset.  Example:

     (poke) 8#B / 2
     4#B

20.2.5.5 Modulus
................

The modulus of two offsets gives you another offset with the expected
semantics.  Examples:

     (poke) 9#b % 1#B
     1#b
     (poke) 1#B % 9#b
     8#b

   The unit of the result is the greatest common divisor of the units of
the operands.


File: poke.info,  Node: Offset Attributes,  Prev: Offset Operations,  Up: Offsets

20.2.6 Offset Attributes
------------------------

The following attributes are defined for offset values.

'size'
     Gives an offset with the storage occupied by the offset.  Examples:

          (poke) 10#B'size
          0x20UL#b
          (poke) 10N#B'size
          0x4UL#b
'magnitude'
     Gives the magnitude part of the offset.  Examples:

          (poke) 10#B'magnitude
          10
          (poke) 2H#b'magnitude
          2H
'unit'
     Gives a number with the unit of the offset, expressed in bits.
     Examples:

          (poke) 10#B'unit
          8UL
          (poke) 2H#b'unit
          1UL
'mapped'
     Always 0 for offsets.  (*note Mapping::).
'length'
     Always '1UL' for integers.


File: poke.info,  Node: Strings,  Next: Arrays,  Prev: Offsets,  Up: The Poke Language

20.3 Strings
============

Poke supports a notion of "strings" which is very similar to the C
programming language: a string value is a sequence of characters that is
terminated by the so-called "null character".

   The standard library provides functions which process strings.  *Note
String Functions::.

* Menu:

* String Literals::		Writing string values.
* String Types::		string.
* String Indexing::		Accessing the characters of a string.
* String Concatenation::        Building new strings.
* String Attributes::           Accessing properties of string values.
* String Formatting::           Composing strings from values.


File: poke.info,  Node: String Literals,  Next: String Types,  Up: Strings

20.3.1 String Literals
----------------------

NULL-terminated sequences of ASCII codes can be denoted using the
following syntax:

     "foo"

   Poke string values are very similar to C strings.  They comprise a
sequence of 8-bit character codes, terminated by the value '0UB'.

   The following escape sequences are supported inside string literals:

'\n'
     Denotes a new line character.
'\t'
     Denotes an horizontal tab.
'\\'
     Denotes a backlash '\' character.
'\"'
     Denotes a double-quote '"' character.
'\NUM'
     NUM is a number in the range 1 to 255 (inclusive) in base 8.
'\xNUM'
     NUM is a number in the range 1 to 255 (inclusive) in base 16.

   Strings cannot contain '0UB' character, and inserting one using
escape sequences ('\0' or '\x0') leads to compilation error.


File: poke.info,  Node: String Types,  Next: String Indexing,  Prev: String Literals,  Up: Strings

20.3.2 String Types
-------------------

Every string value in Poke is of type 'string'.


File: poke.info,  Node: String Indexing,  Next: String Concatenation,  Prev: String Types,  Up: Strings

20.3.3 String Indexing
----------------------

Poke supports accessing the characters in a string using the array
indexing notation.  The indexes are in the '[0,N]' range, where N is the
length of the string minus one.  Note the length doesn't include the
null character, i.e.  it is not possible to access the terminating null.
Examples:

     (poke) "foo"[0]
     0x66UB
     (poke) "foo"[1]
     0x6fUB

   If the passed index is less than zero or it is too big, an
'E_out_of_bounds' exception is raised:

     (poke) "foo"[-1]
     unhandled out of bounds exception
     (poke) "foo"[3]
     unhandled out of bounds exception

Poke also provides a way to refer to a character in a string by the
offset the character occupies in the string.  This is done by using as
index an expression that evaluates to an offset value.  This value is
then implicitly promoted to have an unsigned 64-bit magnitude and unit
bits whenever needed.  If no character starts _exactly_ at the provided
offset then an 'E_out_of_bounds' exception is raised.


File: poke.info,  Node: String Concatenation,  Next: String Attributes,  Prev: String Indexing,  Up: Strings

20.3.4 String Concatenation
---------------------------

Strings can be concatenated using the '+' operator.  This works like
this:

     (poke) "foo" + "bar"
     "foobar"

   Note how the null character terminating the first string is removed.
Therefore, the length of the concatenation of two given strings of
lengths 'N' and 'M' is always 'N+M-1'.

   Concatenation and indexing are useful together for building strings.
A string can be created empty, and additional characters added to it by
means of concatenation:

     (poke) var bytes = "";
     (poke) bytes = bytes + 'x' as string;

   Then, we can retrieve characters from the string we built using
indexing:

     (poke) bytes[0]
     0x78UB

   Additionally, the '*' operator allows to "multiply" a string by
concatenating it with itself a given number of times.  This works like
this:

     (poke) "foo" * 3
     "foofoofoo"
     (poke) "foo" * 0
     ""

   This is useful for building strings whose length is not known at
compile time.  For example:

     fun make_empty_string = (int length) string:
     {
        return " " * length;
     }


File: poke.info,  Node: String Attributes,  Next: String Formatting,  Prev: String Concatenation,  Up: Strings

20.3.5 String Attributes
------------------------

The following attributes are defined for string values.

'length'
     Gives the number of characters composing the string, not counting
     the terminating null.  Examples:

          (poke) "foo"'length
          3UL
          (poke) ""'length
          0UL

'size'
     Gives an offset with the storage occupied by the string.  This
     includes the terminating null.  Examples:

          (poke) "foo"'size
          32UL#b
          (poke) ""'size
          8UL#b
'mapped'
     Always 0 for strings.  (*note Mapping::).


File: poke.info,  Node: String Formatting,  Prev: String Attributes,  Up: Strings

20.3.6 String Formatting
------------------------

Poke provides a built-in function 'format' that can be used in order to
format, or build, a string value that is derived from a set of zero or
more Poke values:

     format (FMT[, VALUE...])

Where FMT is a format string that interpreted verbatim but for
predefined "format tags" which start with '%'.  These format tags are
interpreted especially.  *Note printf::.

   Example:

     var s = format ("Age is %i32d.", 66);

The value of the variable 's' is '"Age is 66."'.


File: poke.info,  Node: Arrays,  Next: Structs,  Prev: Strings,  Up: The Poke Language

20.4 Arrays
===========

Arrays are homogeneous collections of values.

* Menu:

* Array Literals::		Writing array values.
* Array Types::			Bounded and unbounded arrays.
* Casting Arrays::              Converting arrays from one type to another.
* Array Constructors::		Constructing array values.
* Array Comparison::		Comparing array values.
* Array Indexing::		Accessing values stored in arrays.
* Array Trimming::		Working with array pieces.
* Array Elements::		Checking for array elements.
* Array Concatenation::		Concatenating the elements of arrays.
* Array Attributes::		Accessing properties of array values.
* Arrays as Stacks::            Using arrays as stacks.


File: poke.info,  Node: Array Literals,  Next: Array Types,  Up: Arrays

20.4.1 Array Literals
---------------------

Array literals are constructed using the following syntax:

     [EXP,EXP...]

where EXP is an arbitrary expression.

   For example, '[1,2,3]' constructs an array of three signed 32-bit
integers.  Likewise, '['a','b','c']' constructs an array of three
unsigned 8-bit integers (characters).  For convenience, a trailing comma
is accepted but not required.

   The type of the array literal is inferred from the type of its
elements.  Accordingly, all the elements in an array literal must be of
the same type.  Examples of invalid array literals, that will raise a
compilation-time error if evaluated, are:

     [1,2u,3]
     [1,0xffff_ffff,3]
     ['a',"b",'c']

   Array literals must contain at least one element.  Accordingly, '[]'
is not a valid array literal.

   This is how a '3x3' matrix could be constructed using an array of
arrays:

     [[1,2,3],[4,5,6],[7,8,9],]

   It is possible to refer to specific elements when constructing array
literals.  For example, '[1,2,3,.[3] = 4]' denotes the same array as
'[1,2,3,4]'.

   This allows creating arrays without having to specify all its
elements; every unspecified element takes the value of the first
specified element to its right.  For example, '[.[2] = 2]' denotes the
same array as '[2,2,2]'.

   Note that an array element can be referenced more than once.  When
that happens, the final value of the element is the last specified.  For
example, '[1,2,3,.[1]=10]' denotes the array '[1,10,3]'.


File: poke.info,  Node: Array Types,  Next: Casting Arrays,  Prev: Array Literals,  Up: Arrays

20.4.2 Array Types
------------------

There are three different kind of array types in Poke.

   "Unbounded" arrays have no explicit boundaries.  Examples are 'int[]'
or 'Elf64_Shdr[]'.  Arrays can be "bounded by number of elements"
specifying a Poke expression that evaluates to an integer value.  For
example, 'int[2]'.  Finally, arrays can be "bounded by size" specifying
a Poke expression that evaluates to an offset value.  For example,
'int[8#B]'.

20.4.2.1 Writing unbounded array literals
.........................................

The type of an array literal is always bounded by number of elements.
For example, the type of '[1,2,3]' is 'int[3]'.  If what we want is an
unbounded array literal we can obtain it with a case like '[1,2,3] as
int[]'.

20.4.2.2 Array boundaries and closures
......................................

Poke arrays are rather peculiar.  One of their seemingly bizarre
characteristics is the fact that the expressions calculating their
boundaries (when they are bounded) evaluate in their own lexical
environment, which is captured.  In other words: the expressions
denoting the boundaries of Poke arrays conform closures.  Also, the way
they evaluate may be surprising.  This is no capricious.

   When an array type is bounded, be it by number of elements or by
size, the expression indicating the boundary doesn't need to be constant
and it can involve variables.  For example, consider the following type
definition:

     var N = 2;
     type List = int[N*2];

Let's map a 'List' at some offset:

     (poke) List @ 0#B
     [0x746f6f72,0x303a783a,0x723a303a,0x3a746f6f]

   As expected, we get an array of four integers.  Very good, obviously
the boundary expression 'N*2' got evaluated when defining the type
'List', and the result of the evaluation was '4', right?.  Typical
semantics like in my garden variety programming language...?  Right?!?

   Well, not really.  Let's modify the value of 'N' and map a 'List'
again...

     (poke) N = 1
     (poke) List @ 0#B
     [0x746f6f72,0x303a783a]

   Yes, The boundary of the array type changed... on, this is Poke, was
you *really* expecting something typical?  ;)

   What happens is that at type definition time the lexical environment
is captured and a closure is created.  The body of the closure is the
expression.  Every time the type is referred, the closure is
re-evaluated and a new value is computed.

   Consequently, if the value of a variable referred in the expression
changes, like in our example, the type itself gets updated
auto-magically.  Very nice but, why is Poke designed like this?  Just to
impress the cat?  Nope.

   In binary formats, and also in protocols, the size of some given data
is often defined in terms of some other data that should be decoded
first.  Consider for example the following definition of a 'Packet':

     type Packet =
       struct
       {
         byte size;
         byte[size] payload;
       };

   Each packet contains a 8-bit integer specifying the size of the
payload transported in the packet.  The payload, a sequence of 'size'
bytes, follows.

   In struct types like the above, the boundaries of arrays depend on
fields that have been decoded before and that exist, like variables, in
the lexical scope captured by the struct type definition (yes, these are
also closures, but that's for another article.)  This absolutely depends
on having the array types evaluate their bounding expressions when the
type is used, and not at type definition time.

To show this property in action, let's play a bit:

     (poke) var data = byte[4] @ 0#B
     (poke) data[0] = 2
     (poke) data[1] = 3
     (poke) data[2] = 4
     (poke) data[3] = 5
     (poke) dump
     76543210  0011 2233 4455 6677 8899 aabb ccdd eeff
     00000000: 0203 0405 0000 0000 0000 0000 0000 0000
     00000010: 0000 0000 0000 0000 0000 0000 0000 0000
     (poke) var p1 = Packet @ 0#B
     (poke) var p2 = Packet @ 1#B
     (poke) p1
     Packet {size=0x2UB,payload=[0x3UB,0x4UB]}
     (poke) p2
     Packet {size=0x3UB,payload=[0x4UB,0x5UB,0x0UB]}

   Now, let's change the data and see how the sizes of the payloads are
adjusted accordingly:

     (poke) data[0] = 1
     (poke) data[1] = 0
     (poke) p1
     Packet {size=0x1UB,payload=[0x0UB]}
     (poke) p2
     Packet {size=0x0UB,payload=[]}

   So, as we have seen, Poke's way of handling boundaries in array types
allows data structures to adjust to the particular data they contain, so
usual in binary formats.  This is an important feature, that gives Poke
part of its feel and magic.


File: poke.info,  Node: Casting Arrays,  Next: Array Constructors,  Prev: Array Types,  Up: Arrays

20.4.3 Casting Arrays
---------------------

There are two kinds of casts for array values:

   * Cast to array types that may have a different bounding.
   * Cast of array of integers or integral structs to an integral type.

   For example, we have seen that the type of an array literal is always
bounded by a constant number of elements.  Thus the type of '[1,2,3]' is
'int[3]'.

   We could cast the value above to an unbounded array type by doing:

     [1,2,3] as int[]

Or to an array bounded by size:

     [1,2,3] as int[12#B]

   Of course trying to cast an array value to a type for which the
bounding restrictions will fail.  This will give you a compile-time
error:

     [1,2,3] as int[4]

And this will result in a run-time error:

     (poke) [1,2,3] as int[13#B]
     unhandled conversion error exception

   Now let's see how Poke reinterprets integral arrays as integers:

     (poke) [0xdeUB,0xadUB] as uint16
     0xdeadUH
     (poke) [0xdeUB,0xadUB,0UB] as int
     0xdead00

   Trying to cast an array with a size larger than 64-bit will result in
an error:

     (poke) [1,2,3] as int
     unhandled conversion error exception
     arrays bigger than 64-bit cannot be casted to integral types

   It also works for nested arrays and arrays of integral structs (*Note
Integral Structs::):

     (poke) type Foo = struct uint { int16 hi; int16 lo; };
     (poke) [[Foo{ hi=0xdeadH, lo=0xbeefH}],[Foo{}]] as ulong
     0xdeadbeef00000000UL

   The way it works is like putting all array elements in an 'uint<64>'
number and then casting that number to the destination integral type.


File: poke.info,  Node: Array Constructors,  Next: Array Comparison,  Prev: Casting Arrays,  Up: Arrays

20.4.4 Array Constructors
-------------------------

Array literals can only specify arrays which a constant number of
elements.  They also require initial values for their elements, and it
is also not possible to construct an array literal denoting an empty
array of some given type.

   Array constructors provide a suitable way to build such array values.
The syntax is:

     ARRAY_TYPE ([VALUE])

Where ARRAY_TYPE is an array type, or the name of an array type, and
VALUE is an optional argument that specify the value to which the
elements of the new array are initialized.  If no value is provided in
the constructor then default values are calculated.

   If the boundaries of the array can't be satisfied while constructing,
'E_constraint' is raised.

   Examples:

     (poke) int[]()
     []
     (poke) int[2]()
     [0,0]
     (poke) int[2](10)
     [10,10]
     (poke) offset<int,B>[2](16#b)
     [2#B,2#B]
     (poke) string[3]()
     ["","",""]
     (poke) int[][3](int[2](666))
     [[666,666],[666,666],[666,666]]
     (poke) Packet[3]()
     [Packet {...}, Packet {...}, Packet {...}]

   Note that array constructors are implicitly involved when you
construct a struct or union value that contains a field whose type is an
array.  For example, consider the following type:

     type Packet =
       struct
       {
         byte sz;
         byte[sz] data;
       };

When a packet is constructed using 'Packet {}' the 'data' field of the
struct is also constructed, implicitly using a constructor for the array
type 'byte[sz]'.


File: poke.info,  Node: Array Comparison,  Next: Array Indexing,  Prev: Array Constructors,  Up: Arrays

20.4.5 Array Comparison
-----------------------

The equality operator ('==') and the inequality operator ('!=') can be
applied to arrays.  Examples:

     (poke) [1,2,3] == [1,2,3]
     1
     (poke) [[1,2],[3,4]] != [[5,6],[7,8]]
     1

   Note that the array elements are compared recursively.


File: poke.info,  Node: Array Indexing,  Next: Array Trimming,  Prev: Array Comparison,  Up: Arrays

20.4.6 Array Indexing
---------------------

Arrays are indexed using the usual notation, providing an index enclosed
between square brackets with '[' and ']':

     (poke) [1,2,3][0]
     1
     (poke) [1,2,3][8#B]
     2

20.4.6.1 Indexing an array by number of element
...............................................

Indexing by number of element is performed by providing as index an
expression that evaluates to an integral value.  This value is then
implicitly promoted to an unsigned 64-bit integer when needed.

   The valid range for the index is '[0,N]' where N is the number of
elements stored in the array minus one.  If the passed integer is out of
that range, an 'E_out_of_bounds' exception is raised:

     (poke) [1,2,3][-1]
     unhandled out of bounds exception
     (poke) [1,2,3][3]
     unhandled out of bounds exception

20.4.6.2 Indexing an array by offset of element
...............................................

Poke also provides a way to refer to the element of an array by the
offset where the element appears inside the array.  This is done by
providing as index an expression that evaluates to an offset value.
This value is then implicitly promoted to an offset with magnitude
unsigned 64-bit integer and bit unit when needed.

   If there is not element in the indexed array that starts _exactly_ at
the given offset then an 'E_out_of_bounds' exception is raised.


File: poke.info,  Node: Array Trimming,  Next: Array Elements,  Prev: Array Indexing,  Up: Arrays

20.4.7 Array Trimming
---------------------

Indexing is used to fetch elements from arrays.  Another operation,
called "trimming", allows you to extract a subset of the array, as
another array.

   Trims use the following notation, where a range is specified between
square brackets.  The left sides of the range are closed, whereas the
right sides of the range are open:

     (poke) [1,2,3][0:2]
     [1,2]
     (poke) [1,2,3][1:2]
     [2]
     (poke) [1,2,3][0:3]
     [1,2,3]

   If the minimum side of the range is omitted, it is assumed to be
zero.  If the maximum side of the range is omitted, it is assumed to be
the length of the trimmed array:

     (poke) [1,2,3][:2]
     [1,2]
     (poke) [1,2,3][1:]
     [2,3]
     (poke) [1,2,3][:]
     [1,2,3]

   The elements of the base array and the trimmed sub-array are copied
by shared value, exactly like when passing arguments to functions.  This
means that for simple types, copies of the elements are done:

     (poke) var a = [1,2,3]
     (poke) var s = a[1:2]
     (poke) s[0] = 66
     (poke) a
     [1,2,3]

   However, for complex types like arrays and structs, the values are
shared:

     (poke) var a = Packet[] @ 0#B
     (poke) var s = a[1:2]
     (poke) s[0].field = 66
     (poke) a[1].field
     66

   There is an alternative syntax that can be used in order to denote
trims, in which the length of the trim is specified instead of the index
of the second element.  It has this form:

     (poke) [1,2,3][0+:3]
     [1,2,3]
     (poke) [1,2,3][1+:2]
     [2,3]
     (poke) [1,2,3][1+:0]
     []


File: poke.info,  Node: Array Elements,  Next: Array Concatenation,  Prev: Array Trimming,  Up: Arrays

20.4.8 Array Elements
---------------------

The 'in' operator can be used to determine whether a given element is
stored in an array.  Examples:

     (poke) 2 in [1,2,3]
     1
     (poke) 2 in [4,5,6]
     0
     (poke) 10#b in [1#B] #! Promotion doesn't happen. !#
     <stdin>:1:1: error: invalid operand in expression
     <stdin>:1:1: error: expected offset<int<32>,8>, got offset<int<32>,1>


File: poke.info,  Node: Array Concatenation,  Next: Array Attributes,  Prev: Array Elements,  Up: Arrays

20.4.9 Array Concatenation
--------------------------

The operator '+' can be used to build new arrays resulting from the
concatenation of the elements of two arrays given as operands:

     (poke) [1,2] + [3,4,5]
     [1,2,3,4,5]

The two arrays given as operands shall have the same elements of the
same type.  The resulting array is always unbounded.


File: poke.info,  Node: Array Attributes,  Next: Arrays as Stacks,  Prev: Array Concatenation,  Up: Arrays

20.4.10 Array Attributes
------------------------

The following attributes are defined for array values.

'size'
     Gives an offset with the storage occupied by the complete array.
     Example:

          (poke) [1,2,3]'size
          96UL#b
'length'
     Gives the number of elements stored in the array.  Example:

          (poke) [1,2,3]'length
          3
'mapped'
     Boolean indicating whether the array is mapped.  Examples:

          (poke) var a = [1,2,3]
          (poke) var b = int[3] @ 0#B
          (poke) a'mapped
          0
          (poke) b'mapped
          1
'strict'
     Boolean indicating whether the array is mapped in strict mode.
     Examples:

          (poke) var a = int[3] @ 0#B
          (poke) a'strict
          1
          (poke) var a = int[3] @! 0#B
          (poke) a'strict
          0
'elem (IDX)'
     Element occupying the position IDX in the array.  Note that this
     attribute evaluates to a value of type 'any'.
'eoffset (IDX)'
     Offset of the element identified by the index IDX in the array.
     Examples:

          (poke) [1,2,3]'eoffset (1)
          32#b

     If the provided index is out of bounds then 'E_out_of_bounds' is
     raised.
'esize (IDX)'
     Size of the element identified by the index IDX in the array.
     Examples:

          (poke) ["foo","x",""]'esize (1)
          16#b

     If the provided index is out of bounds then 'E_out_of_bounds' is
     raised.
'ename (IDX)'
     The string '"[IDX]"'.

     If the provided index is out of bounds then 'E_out_of_bounds' is
     raised.


File: poke.info,  Node: Arrays as Stacks,  Prev: Array Attributes,  Up: Arrays

20.4.11 Arrays as Stacks
------------------------

Array values can be manipulated as stacks using two operators: 'apush'
and 'apop'.

   The 'apush' operator gets an array and a value and appends the value
into the array.  Note it has a destructive side-effect in the array
value, and also it returns the modified value:

     (poke) var a = [1,2,3]
     (poke) apush (a, 4)
     [1,2,3,4]
     (poke) a
     [1,2,3,4]

   the 'apop' operators gets an array and removes the last value of the
array.  If the given array is empty then 'E_out_of_bounds' is raised.
As with 'apush', the operation has the side effect of modifying the
given array and also it returns the popped element:

     (poke) var a = [1,2,3]
     (poke) apop (a)
     3
     (poke) apop (a)
     2
     (poke) apop (a)
     1
     (poke) apop (a)
     unhandled out of bounds exception


File: poke.info,  Node: Structs,  Next: Types,  Prev: Arrays,  Up: The Poke Language

20.5 Structs
============

Structs are the main abstraction that Poke provides to structure data.
They contain heterogeneous collections of values.

* Menu:

* Struct Types::		Simple structs.
* Struct Constructors::		Constructing struct values.
* Struct Comparison::		Comparing struct values
* Field Endianness::            Specifying the endianness of integral fields.
* Accessing Fields::            Getting and fetching the values of fields.
* Field Constraints::		Specifying data integrity.
* Field Initializers::		Initial values for fields.
* Field Labels::		Explicit offsets for fields.
* Pinned Structs::		Fix the offset of fields.
* The OFFSET variable::		Accessing the offset of the current field.
* Integral Structs::		Composite data stored in integers.
* Unions::			Dealing with conditional data.
* Union Constructors::          Constructing union values.
* Integral Unions::		Variants of composite data stored in integers.
* Optional Fields::		Fields that may or may not exist.
* Casting Structs::		Converting structs from one type to another.
* Declarations in Structs::	Declaring stuff within a struct.
* Methods::			Declaring struct methods.
* Computed Fields::             Simulating fields with methods.
* Struct Attributes::		Accessing properties of struct values.


File: poke.info,  Node: Struct Types,  Next: Struct Constructors,  Up: Structs

20.5.1 Struct Types
-------------------

A simple struct type definition in Poke looks like:

     type Packet =
       struct
       {
         byte magic;
         uint<16> length;
         byte[length] data;
       }

   The above defines a "Packet", which consists on a magic number
encoded in a byte, a length encoded in an unsigned 16-bit integer, and
an array of 'length' bytes, which is the payload of the packet.

   Each entry in the struct type above defines a "struct field".

   Each field has a type, which is mandatory, and a name, which is
optional.  Fields without names are not accessible (not even within the
struct itself) but they are handy for expressing esoteric padding.
*Note Padding and Alignment::.  Example:

     type Imm64 =
       struct
       {
         uint<32> lo;
         uint<32>;
         uint<32> hi;
       }

   It is not allowed to have several fields with the same name in the
same struct.  The compiler will complain if it finds such an occurrence.


File: poke.info,  Node: Struct Constructors,  Next: Struct Comparison,  Prev: Struct Types,  Up: Structs

20.5.2 Struct Constructors
--------------------------

Once a struct type gets defined, there are two ways to build struct
values from it.  One is "mapping".  *Note Mapping Structs::.  The other
is using a "struct constructor", which is explained in this section.

   Struct constructors have the following form:

     TYPE_NAME { [FIELD_INITIALIZER,]... }

where each FIELD_INITIALIZER has the form:

     [FIELD_NAME=]EXP

   Note how each field has an optional name FIELD_NAME and a value EXP.
The expression for the value can be of any type.  For convenience, a
trailing comma is accepted but not required.

   Suppose for example that we have a type defined as:

     type Packet =
       struct
       {
         uint<16> flags;
         byte[32] data;
       }

   We can construct a new packet, with all its fields initialized to
zero, like this:

     (poke) Packet {}
     Packet {
       flags=0x0UH,
       data=[0x0UB,0x0UB,0x0UB,0x0UB,0x0UB,...]
     }

   In the constructor we can specify initial values for some of the
fields:

     (poke) Packet { flags = 0x8 }
     Packet {
       flags=0x8UH,
       data=[0x0UB,0x0UB,0x0UB,0x0UB,0x0UB,...]
     }

   It is not allowed to specify initializers that are not part of the
type being constructed:

     (poke) Packet { foo = 10 }
     <stdin>:1:10: error: invalid struct field `foo' in constructor
     Packet { foo = 10 };
              ^~~

   As we shall see later, many struct types define constraints on the
values their fields can hold.  This is a way to implement data
integrity.  While building struct values using constructors, these
constraints are taken into account.  For example, given the following
struct type:

     type BPF_Reg =
       struct
       {
        uint<4> code : code < 11;
       };

we will get a constraint violation exception if we try to construct an
'BPF_Reg':

     (poke) BPF_Reg { code = 20 }
     unhandled constraint violation exception


File: poke.info,  Node: Struct Comparison,  Next: Field Endianness,  Prev: Struct Constructors,  Up: Structs

20.5.3 Struct Comparison
------------------------

The equality operator ('==') and the inequality operator ('!=') can be
applied to struct values.  Examples:

     (poke) E_eof == E_eof
     1
     (Poke) Packet { payload=0x3 } != Packet { payload=0x4 }
     1

   The struct values are compares recursively.


File: poke.info,  Node: Field Endianness,  Next: Accessing Fields,  Prev: Struct Comparison,  Up: Structs

20.5.4 Field Endianness
-----------------------

By default fields are accessed in IO space using the current default
endianness.  However, it is possible to annotate fields with an explicit
endianness, like in:

     type Foo =
       struct
       {
         little int a;
         big int b;
         int c;
       };

   In the example above, the field 'a' will be stored using
little-endian, the field 'b' will be stored using big-endian, and the
field 'c' will be stored using whatever current endianness.

   The endianness annotations can be used in any kind of fields, like
offsets, arrays and structs, and will impact the storage ofintegral
fields defined in them.

   When endianness annotations are used in struct fields which are
themselves structs, they effectively change the default endianness in
the contained struct.  Therefore, in the following struct type:

     type Bar =
       struct
       {
         little struct
         {
           big int a;
           int b;
         } f;
         int c;
       }

'a' is big endian, but 'b' is little endian.

   However, note that the scope of the 'big' and 'little' annotations is
lexical.  Therefore, in these types:

     type Foo =
       struct
       {
         int a;
         int b;
       };

     type Bar =
       struct
       {
         big Foo f;
         int c;
       };

The endianness of the 'a' and 'b' fields stored in 'f' is the default
endianness, not 'big'.


File: poke.info,  Node: Accessing Fields,  Next: Field Constraints,  Prev: Field Endianness,  Up: Structs

20.5.5 Accessing Fields
-----------------------

Poke uses the usual dot-notation to provide access to struct fields.
Examples:

     (poke) var s = struct { i = 10, l = 20L }
     (poke) s.i
     10
     (poke) s.l
     20L

   Writing to fields is achieved by having the field reference in the
left side of an assignment statement:

     (poke) s.i = 100
     (poke) s.l = 200
     (poke) s
     struct {i=100,l=200L}


File: poke.info,  Node: Field Constraints,  Next: Field Initializers,  Prev: Accessing Fields,  Up: Structs

20.5.6 Field Constraints
------------------------

It is common for struct fields to be constrained to their values to
satisfy some conditions.  Obvious examples are magic numbers, and
specification-derived constraints.

   In Poke you can specify a field's constraint using the following
syntax:

     FIELD_TYPE FIELD_NAME : EXPRESSION ;

where EXPRESSION is an arbitrary Poke expression, that should evaluate
to an integer value.  The result is interpreted as a boolean.  As an
example, this is how the ELF magic number is checked for:

     type Ctf_Preamble =
       struct
       {
         uint<16> ctp_magic : ctp_magic == CTF_MAGIC;
         byte ctp_version;
         byte ctp_flags;
       };

   The constraint expression will often include the field where it is
installed, but that's not mandatory.

   Field constraints play an important role in mapping.  On one side, a
map will fail if there is some constraint that fails.  On the other,
they guide the mapping of unbounded arrays.  *Note Mapping Arrays::.

   Another common usage of constraint expressions is to alter the global
state after decoding a field.  For example, this is how mapping an ELF
header sets the current endianness, depending on the value of 'ei_data':

     byte ei_data : ei_data == ELFDATA2LSB       \
                    ? set_endian (ENDIAN_LITTLE) \
                    : set_endian (ENDIAN_BIG);

   Note that 'set_endian' always returns '1'.


File: poke.info,  Node: Field Initializers,  Next: Field Labels,  Prev: Field Constraints,  Up: Structs

20.5.7 Field Initializers
-------------------------

We saw that field constraints are useful to express magic numbers, which
are pretty common in binary formats.  Imagine a package has a marker
byte at the beginning, which should always be '0xff'.  We could use a
constraint like in:

     type Packet =
       struct
       {
         byte marker : marker == 0xff;
         byte length;
         byte[length] payload;
       };

   This works well when mapping packages.  The constraint is checked and
a constraint violation exception is raised if the first byte of the
alleged package is not '0xff'.

   However, suppose we want to construct a new 'Package', with no
particular contents.  We would use a constructor, but unfortunately:

     (poke) Packet { }
     unhandled constraint violation exception

   What happened?  Since we didn't specify a value for the marker in the
struct constructor, a default value was used.  The default value for an
integral type is zero, which violates the constraint associated with the
field.  Therefore, we would need to remember to specify the marker,
every time we construct a new packet:

     (poke) Packet { marker = 0xff }
     Packet {
       marker=0xffUB,
       length=0x0UB,
       payload=[]
     }

   Unfortunately, such markers and magic numbers are not precisely very
memorable.  To help with this, Poke has the notion of "type field
initializers".  Let's use one in our example:

     type Packet =
       struct
       {
         byte marker = 0xff;
         byte length;
         byte[length] payload;
       };

   Note how the syntax is different than the one used for constraints.
When a field in a struct type has an initializer, the struct constructor
will use the initializer expression as the initial value for the field.
For example:

     (poke) Packet {}
     Packet {
       marker=0xffUB,
       length=0x0UB,
       payload=[]
     }

   It is possible to specify both a constraint and an initializer in the
same field.  Suppose we want to support several kinds of packets,
characterized by several markers.  The supported markers are however a
closed set.  We could do it like this:

     type Packet =
       struct
       {
         byte marker = 0xff : marker in [0xffUB, 0xfeUB];
         byte length;
         byte[length] payload;
       };

   Note however that struct mappers do not make use of field
initializers, since the mapped IO space provides values for all the
fields in the struct type.  If we mapped the 'Packet' type above, we
would need to add also a constraint to make sure the value of 'marker'
is the right one.  This also applies to constructing 'Packet' types
where an initial value is explicitly specified.  We could do it by
specifying both an initial value, and a constraint expression:

     type Packet =
       struct
       {
         byte marker = 0xff : marker == 0xff;
         byte length;
         byte[length] payload;
       };

   This idiom is to common that Poke provides a more compact syntax to
denote it, that avoids verbosity and replicated logic:

     type Packet =
       struct
       {
         byte marker == 0xff;
         byte length;
         byte[length] payload;
       };

   It is considered good practice to design struct types in a way that a
constructor with no arguments will result in something usable.


File: poke.info,  Node: Field Labels,  Next: Pinned Structs,  Prev: Field Initializers,  Up: Structs

20.5.8 Field Labels
-------------------

In structs, each field is associated with an offset, which is relative
to the beginning of the struct.  This is the offset used when reading
and writing the field from/to the IO space when mapping.

   The offset is reset to zero bits at the beginning of the struct type,
and it is increased by the size of the fields:

     struct
     {
                     /* Offset: 0#b */
         uint<1> f1; /* Offset: 1#b */
         sint<7> f2; /* Offset: 1#B */
         int     f3; /* Offset: 5#B */
         Bar     f4; /* Offset: 23#B */
     }

   It is possible to specify an alternative offset for a field using a
"field label".

   Consider for example an entry in an ELF symbol table.  Each entry has
a 'st_info' field which is 64-bits long, that in turn can be interpreted
as two fields 'st_bind' and 'st_type'.

   The obvious solution is to encode 'st_info' as a sub-struct that is
integral, like this:

     struct
     {
       elf32_word st_name;
       struct uint<64>
       {
         uint<60> st_bind;
         uint<4> st_type;
       } st_info;
     }

   This makes the value of 'st_info' easily accessible as an integral
value.  But we may prefer to use labels instead:

     struct
     {
       elf32_word st_name;
       elf64_word st_info;
       uint<60> st_bind @ 4#B;
       uint<4> st_type @ 4#B + 60#b;
     }

   The resulting struct has fields 'st_info', 'st_bind' and 'st_type',
with the last two overlapping the first.

   Field labels are also useful in the rare cases where a variable part
of a struct depends on some data that comes _after_ it.  This happens
for example in the COFF "line number" structures, which are defined like
this in C:

     struct external_lineno
     {
       union
       {
         char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/
         char l_paddr[4];  /* (physical) address of line number */
       } l_addr;

       char l_lnno[L_LNNO_SIZE]; /* line number  */
     };

i.e.  the 'l_addr' field is to be interpreted as an index in a table or
as a physical address depending on the value of 'l_lnno'.

   This is one way to denote the above data structure using Poke struct
labels:

     type COFF_LINENO_32 =
       struct
       {
         uint<32> l_lnno  4#B; /* Line number.  */

         union
         {
           uint<32> l_symndx : l_lnno == 0;
           offset<uint<32>,B> l_paddr;
         } l_addr  0#B;
       };

Note how the 'l_lnno' field is stored after 'l_addr' even if they appear
in reverse order in the struct definition.  This allows us to refer to
'l_nno' in the constraints for the union fields.


File: poke.info,  Node: Pinned Structs,  Next: The OFFSET variable,  Prev: Field Labels,  Up: Structs

20.5.9 Pinned Structs
---------------------

Pinned structs is a convenient way to write struct types where the
offset of all its fields is zero.  They are equivalent to C unions.

   For example, consider the '_u' field below in a CTF type description:

     type Ctf_Stype_V1 =
       struct
       {
         Ctf_Name ctt_name;
         Ctf_Info_V1 ctt_info;
         pinned struct
         {
           uint32 _size;		/* Size of entire type in bytes.  */
           uint32 _type;		/* Reference to another type.  */
         } _u;
       };

   Note that integral structs cannot be pinned.  *Note Integral
Structs::.  And field labels are not allowed in pinned structs.


File: poke.info,  Node: The OFFSET variable,  Next: Integral Structs,  Prev: Pinned Structs,  Up: Structs

20.5.10 The OFFSET variable
---------------------------

The offset of the current field being mapped or constructed, relative to
the beginning of the struct, is at all times available in a variable
called 'OFFSET'.  This is useful in situations where we need that
information in a constraint expression, the boundary of an array, an
initialization value, or the like.

   For example, what follows is a typical usage of OFFSET in order to
introduce some padding in a struct:

     type Elf64_Note =
       struct
       {
         [...]

         Elf64_Xword name;
         byte[alignto (OFFSET, 4#B)] padding;

         [...]
       };

   The value of this variable changes every time a new field is mapped
or constructed, so writing to it will only have effect until the next
field is processed: at that time the value will be overwritten.


File: poke.info,  Node: Integral Structs,  Next: Unions,  Prev: The OFFSET variable,  Up: Structs

20.5.11 Integral Structs
------------------------

Integral structs are useful to cover cases where data is stored in
composited integral containers, i.e.  where data is structured within
stored integers.

   Basically, when we structure data using Poke structs, arrays and the
like, we often use the same structure than a C programmer would use.
For example, to model ELF RELA structures, which are defined in C like:

     type struct
       {
         Elf64_Addr   r_offset;  /* Address */
         Elf64_Xword  r_info;    /* Relocation type and symbol index */
         Elf64_Sxword r_addend;  /* Addend */
       } Elf64_Rela;

we could use something like this in Poke:

     type Elf64_Rela =
       struct
       {
         Elf64_Addr r_offset;
         Elf64_Xword r_info;
         Elf64_Sxword r_addend;
       };

   Here the Poke struct type is pretty equivalent to the C incarnation.
In both cases the fields are always stored in the given order,
regardless of endianness or any other consideration.

   However, there are situations where stored integral values are to be
interpreted as composite data.  This is the case of the 'r_info' field
above, which is a 64-bit unsigned integer ('Elf64_Xword') which is
itself composed by several fields, depicted here:

      63                                          0
     +----------------------+----------------------+
     |       r_sym          |      r_type          |
     +----------------------+----------------------+
      MSB                                       LSB

   In order to support this kind of composition of integers, C
programmers usually resort to either bit masking (most often) or to the
often obscure and undefined behaviour-prone C bit fields.  In the case
of ELF, the GNU implementations define a few macros to access these
"sub-fields":

     #define ELF64_R_SYM(i)         ((i) >> 32)
     #define ELF64_R_TYPE(i)        ((i) & 0xffffffff)
     #define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type))

   Where 'ELF64_R_SYM' and 'ELF64_R_TYPE' are used to extract the fields
from an 'r_info', and 'ELF64_R_INFO' is used to compose it.  This is
typical of C data structures.

   We could of course mimic the C implementation in Poke:

     fun Elf64_R_Sym = (Elf64_Xword i) uint<32>:
        { return i .>> 32; }
     fun Elf64_R_Type = (Elf64_Xword i) uint<32>:
        { return i & 0xffff_ffff; }
     fun Elf64_R_Info = (uint<32> sym, uint<32> type) Elf64_Xword:
        { return sym as Elf64_Xword <<. 32 + type; }

   However, this approach has a huge disadvantage: since we are not able
to encode the logic of these "sub-fields" in proper Poke fields, they
become second class citizens, with all that implies: no constraints on
their own, can't be auto-completed, can't be assigned individually, etc.

   This is where "integral structs" come to play.  These are structs
that are defined exactly like your garden variety Poke structs, with a
small addition:

     type Elf64_RelInfo =
       struct uint<64>
       {
         uint<32> r_sym;
         uint<32> r_type;
       };

   Note the 'uint<64>' addition after 'struct'.  This can be any integer
type (signed or unsigned).  The fields of an integral struct should be
integral themselves (this includes both integers and offsets) and the
total size occupied by the fields should be the same size than the one
declared in the struct's integer type.  This is checked and enforced by
the compiler.

   The Elf64 RELA in Poke can then be encoded like:

     type Elf64_Rela =
       struct
       {
         Elf64_Addr r_offset;
         struct Elf64_Xword
         {
           uint<32> r_sym;
           uint<32> r_type;
         } r_info;
         Elf64_Sxword r_addend;
       };

   When an integral struct is mapped from some IO space, the total
number of bytes occupied by the struct is read as a single integer
value, and then the values of the fields are extracted from it.  A
similar process is using when writing.  That is what makes it different
with respect a normal Poke struct.

   Consider for example we have the following sequence of bytes in our
IO space (like a file):

     0x10 0x20 0x30 0x40  0x50 0x60 0x70 0x80

   Let's see what happens when we map the integral struct above, in both
big and little endian:

     (poke) .set endian big
     (poke) Elf64_RelInfo @ 0#B
     Elf64_RelInfo {
       r_sym=0x10203040U,
       r_type=0x50607080U
     }
     (poke) .set endian little
     (poke) Elf64_RelInfo @ 0#B
     Elf64_RelInfo {
       r_sym=0x80706050U,
       r_type=0x40302010U
     }

   Looks good.  For comparison, this is what happens when we do the same
with an "equivalent" (not really) non-integral struct operating on the
same data:

     type Elf64_RelInfoBogus =
       struct
       {
         uint<32> r_sym;
         uint<32> r_type;
       };

   We would get:

     (poke) .set endian big
     (poke) Elf64_RelInfoBogus @ 0#B
     Elf64_RelInfoBogus {
       r_sym=0x10203040U,
       r_type=0x50607080U
     }
     (poke) .set endian little
     (poke) Elf64_RelInfoBogus  0#B
     Elf64_RelInfoBogus {
       r_sym=0x40302010U,
       r_type=0x80706050U
     }

   In this case, and unlike with integral structs, the endianness
impacts the bytes of the individual fields, not of the whole struct.

   As you can see, integral structs can be used to denote a lot of
commonly found idioms in data structures and this includes a lot of what
is sometimes denoted in C bit field.  However, one should be cautious
when "translating" C structures to Poke, especially when the C
programmer has not been careful and incurres in sometimes obscure
implementation-defined behavior.  An integral struct is not always the
right abstraction to use when we see a C bit field!

   As an example of the above, consider the following C struct:

     struct regs
     {
      __u8 dst_reg:4;
      __u8 src_reg:4;
     };

   Certain virtual architecture uses that data layout to store registers
in instructions (no comment.)  Thing is, in bit fields like the above
with sub-byte field sizes, the ordering of the fields is not clearly
defined, and ultimately what order to use is up to the compiler, i.e.
to lore and tradition.  As it happens, GCC encodes 'src_reg' in the most
significant nibble of the byte and 'dst_reg' in the least significant
nibble of the byte when compiling for a little-endian target, and the
other way around when compiling for a little-endian target.  (I may have
had that wrong, this always confuses me.)

   How could we encode the C struct regs in Poke?  Let's see.

   A normal Poke struct clearly won't do it:

     type RegsBogus1 =
       struct
       {
         uint<4> src;
         uint<4> dst;
       };

   The reason being, the ordering of src and dst does not change when
you switch endianness (since this is Poke, we can in fact talk about
real ordering of bits)...  remember, poke is WYPIWIG (what you poke is
what you get) ;)

   What about an integral struct?

     type RegsBogus2 =
       struct uint<8>
      {
         uint<4> src;
         uint<4> dst;
      };

   This won't work either.  In fact, the net effect of the normal
decoding of the normal struct type RegsBogus1 and the
map-an-integer-and-extract-fields decoding of the integral struct
RegsBogus2 is in this case totally equivalent.

   A solution is to use a normal struct, and field labels:

     type RegsBogus =
       struct
       {
         var little_p = (get_endian == ENDIAN_LITTLE);

         uint<8> src @ !little_p * 4#b;
         uint<8> dst @ little_p * 4#b;
       };

   At this point, you may be wondering: is there anything particular in
a field defined in an integral struct?  The answer is: no, not at all.
These are regular, first-class fields.  Likewise, integral structs are
perfectly regular structs.  And of course, since this is poke, you can
have integral structs of say, 11 bits, or 3 bits, map them at offsets
not aligned to bytes, and all the typical poke-atrocities that we enjoy
so much.

   However, there exist a few restrictions, some of them fundamental,
the others to be lifted eventually:

   - Integral structs can only have integral fields.  This includes
     offsets and integral structs.
   - No labels are allowed in the fields of integral structs.  This is
     not a fundamental limitation, and may be supported at some point.
   - No optional fields are supported in integral structs.  Support for
     this is actually partially implemented (the mapper supports them
     but not the writer) and most probably will be completed one of
     these days.

   Integral structs can be converted from/to integral structs to/from
integers, so we can do things like:

     rel.r_info as uint<64>;

   And also automatic promotions in arithmetic operators, like:

     rel.r_info + 20 * rel.r_info.r_type

   Integers can also be "structured" into integral structs:

     (poke) 0xdeadbeef as Elf32_RelInfo
     Elf32_RelInfo {
       r_sym=(uint<24>) 0xdeadbe,
       r_type=0xefUB
     }


File: poke.info,  Node: Unions,  Next: Union Constructors,  Prev: Integral Structs,  Up: Structs

20.5.12 Unions
--------------

Union types are defined much like struct types, using a very similar
syntax:

     union
     {
       [... elements ...]
     }

Like in structs, the main kind of elements are fields.  However, unlike
in structs, the fields in an union type denote "alternatives".  At any
given time, only one alternative is selected, and therefore union
_values_ have only one field.

   Which of the several alternatives is selected is determined by the
data integrity defined by means of constraint expressions and other
means.  Alternatives are considered in turn, in written order, and the
first alternative that can be used without triggering a constraint
violation exception is selected.

   It makes little sense to mark union types as pinned, since whatever
alternative is chosen will always be located at the beginning of the
union.  To avoid unnecesary confusion, the Poke compiler will emit an
error if you try to tag an union as pinned.

   Similarly, labels are not allowed in union alternatives.


File: poke.info,  Node: Union Constructors,  Next: Integral Unions,  Prev: Unions,  Up: Structs

20.5.13 Union Constructors
--------------------------

Constructing union values is very similar to constructing struct values:

     TYPE_NAME { [FIELD_INITIALIZER] }

   The main difference is that union constructors require either exactly
one field initializer, or none.  Specifying initialization values for
more than one field doesn't make sense in the case of unions.

   Suppose we have the following union type:

     type Packet =
       union
       {
         byte b : b > 0;
         int k;
       };

   If we try to construct a 'Packet' with an invalid 'b', we get a
constraint error:

     (poke) Packet {b = 0}
     unhandled constraint violation exception

The reason why 'k' is not chosen is because we specified 'b' in the
union constructor: we explicitly as for a 'Packet' of that kind, but the
data we provide doesn't accommodate to that.  If we wanted another kind
of value, we could of course specify an initial value for 'k' instead:

     (poke) Packet {k = 10}
     Packet {
       k=10
     }

   If no field initializer is specified in an union constructor then
each alternative is tried assuming all fields have default values, which
in the case of integral types is a zero:

     (poke) Packet {}
     Packet {
       k=0
     }

Therefore the alternative 'b' is considered invalid (it has to be bigger
than 0) and 'k' is chosen instead.


File: poke.info,  Node: Integral Unions,  Next: Optional Fields,  Prev: Union Constructors,  Up: Structs

20.5.14 Integral Unions
-----------------------

Integral unions are useful to cover cases where we have variants of data
encoded in integers.  One example could be CPU instructions encoded as
16-bit or 32-bit numbers.

     type InstructionFormat_1 =
       struct uint<32>
       {
         uint<20> imm31_12;
         uint<5>  rd;
         uint<7>  opcode : valid_opcode_for_format_1 (opcode);
       };

     type InstructionFormat_2 =
       struct uint<32>
       {
         uint<7> funct7;
         uint<5> rs2;
         uint<5> rs1;
         uint<3> funct3;
         uint<5>  rd;
         uint<7>  opcode : valid_opcode_for_format_2 (opcode);
       };

     type Instruction =
       union uint<32>
       {
         InstructionFormat_1 f1;
         InstructionFomrat_2 f2;
       };

   Like integral structs, integral unions can be casted to/from
integers; e.g., '3211411U as Instruction' will create an 'Instruction'
union.

   Like integral structs, integral unions can have fields of the
following types: integral, offset, integral struct or union.


File: poke.info,  Node: Optional Fields,  Next: Casting Structs,  Prev: Integral Unions,  Up: Structs

20.5.15 Optional Fields
-----------------------

Sometimes a field in a struct is optional, i.e.  it exists or not
depending on some criteria.  A good example of this is the "extended
header" in a MP3 id3v2 tag.  From the specification:

     The second bit (bit 6) indicates whether or not the header is followed
     by an extended header. The extended header is described in section
     3.2. A set bit indicates the presence of an extended header.

   In order to express this in a Poke struct type, we could of course
use an union, like:

     type ID3V2_Tag =
       struct
       {
         ID3V2_Hdr hdr;
         union
         {
           ID3V2_Ext_Hdr hdr : hdr.extended_hdr_present;
           struct {};
         } ext;
         ...
       }

   That's it, we use an union with an empty alternative.  However, this
approach has two problems.  First, it is a bit cumbersome to write and
it becomes necessary to introduce an intermediate named field like 'ext'
above.  Second, and most importantly, the constraint expression in the
union alternative is evaluated only once the alternative has been
already decoded.

   Therefore Poke provides a more convenient way to denote this:

     type ID3V2_Tag =
       struct
       {
          ID3V2_Hdr hdr;
          if (hdr.extended_hdr_present)
            IDV2_Ext_Hdr ext_hdr;
          ...
       }

In the example above 'ext_hdr' will be decoded only if
'hdr.extended_hdr_present' is true, which is what we want.

   Sometimes, however, we really need to decode a field to decide
whether it is present or absent in the final struct.  In these cases, we
can use a suffix syntax:

     type ID3V2_Tag =
       struct
       {
          ID3V2_Hdr hdr;
          IDV2_Ext_Hdr ext_hdr if hdr.extended_hdr_present
                                  && ext_hdr.invisible;
          ...
       }

Note how in this example the field 'ext_hdr' can appear itself in the
conditional expression.

   If both a constraint and a suffix optional field expression are
specified, the second should follow the first.

   One important characteristic of optional fields with suffix
expressions to keep in mind is that they are always constructed or
mapped, even when they are omitted.  This is because, generally
speaking, the value of an optional field may be necessary in order to
determine whether the optional field is present or not.

   This may result on unexpected results for the unaware pokist, like in
the example below:

     struct
     {
       Header hdr;
       byte[hdr.len - hdr.padding] data if hdr.len >= hdr.padding;
     }

where the array index may underflow if 'hdr.len' is less or equal than
'hdr.padding'.

   The obvious solution for this problem is to use a prefix conditional
expression instead.

   For obvious reasons, optional fields are not allowed in unions.


File: poke.info,  Node: Casting Structs,  Next: Declarations in Structs,  Prev: Optional Fields,  Up: Structs

20.5.16 Casting Structs
-----------------------

It is possible to cast a struct of some particular type into another
struct type (but not to an union.)  Examples:

     (poke) type Foo = struct { int i; int j; };
     (poke) type Bar = struct { int k; int j; };
     (poke) Bar {j=2} as Foo {}
     Foo {i=0,j=2}

   The semantics of the cast are exactly the same than constructing a
struct of the target type using the struct provided as an expression to
the cast.

   This means that some fields in the original struct may be "lost" when
the struct is converted to the new type.  Consider the following two
definitions:

     type Foo = struct { int i; long j; };
     type Bar = struct { int i; }

   Let's cast some values and see what we obtain:

     (poke) Bar {}
     Bar {
       i=0x0
     }
     (poke) Bar {} as Foo
     Foo {
       i=0x0,
       j=0x0L
     }
     (poke) Foo {} as Bar
     Bar {
       i=0x0
     }

   It is possible to cast an integral struct into an integral type.  The
value to cast is extracted from the struct fields, and then it is
converted to the target type.

   Given the following integral struct type:

     type Foo =
       struct int<64>
       {
         int<32> f1;
         uint<32> f2;
       };

We can operate:

     (poke) Foo { f1 = 1, f2 = 1 } as uint<64> + 2
     0x100000003UL

   Conversely, it is possible to cast an integral value to an integral
struct:

     (poke) 0x100000003UL as Foo
     Foo {
       f1=0x1,
       f2=0x3U
     }


File: poke.info,  Node: Declarations in Structs,  Next: Methods,  Prev: Casting Structs,  Up: Structs

20.5.17 Declarations in Structs
-------------------------------

Type declarations, variable declarations and function declarations are
all allowed inside struct and union types.  The scope of the entity
being declared spans from the declaration until the end of the struct or
union type being defined.

   Functions can't set fields defined in the struct type.


File: poke.info,  Node: Methods,  Next: Computed Fields,  Prev: Declarations in Structs,  Up: Structs

20.5.18 Methods
---------------

Methods in structs can be defined using the 'method' keyword in
definitions like this:

     method IDENTIFIER = FUNCTION_BODY

where FUNCTION_BODY is the body of a function.  *Note Function
Declarations::.

   When invoked, a method gets an implicit _last_ argument which is the
struct value whose method is being used.

   Methods can refer to the fields of the containing struct type that
have been defined before the method itself, by name.

   Additionally, the containing struct can be referred explicitly under
the name 'SELF' in the body of the method.  'SELF' has type 'any'.


File: poke.info,  Node: Computed Fields,  Next: Struct Attributes,  Prev: Methods,  Up: Structs

20.5.19 Computed Fields
-----------------------

A "computed field" declaration in a struct or union type has the form:

     computed FIELD_TYPE FIELD_NAME;

Where FIELD_TYPE is a type specifier denoting the type of the computed
field, and FIELD_NAME is an identifier.  Note that, unlike regular
fields, computed fields cannot have endianness annotations, constraints
defined for them, cannot be optional, nor have initialization values.

   Computed fields are not really stored in the corresponding struct
values: their value is computed every time they are referred, by
invoking a couple of methods that the user should define:

   - A *getter* method with name 'get_FIELD_NAME' and signature
     '()FIELD_TYPE'.

     This getter is used to compute the value of the computed field when
     it is referenced as a r-value.
   - A *setter* method with name 'set_FIELD_NAME' and signature
     '(FIELD_TYPE)void'.

     This setter is called when the computed field is assigned to in a
     l-value.

   For example, consider the following struct denoting a RISC-V
instruction where the immediate is distributed in several chunks:

     type RV32_InsnFmt_J = struct uint<32>
       {
         uint<1>   imm20;
         uint<10>  imm10_1;
         uint<1>   imm11;
         uint<8>   imm19_12;
         RV_Reg    rd;
         RV_Opcode opcode : opcode in RV_OPCODES_J;

         computed int<32> imm;

         method get_imm = int<32>:
         {
           return imm20:::imm19_12:::imm11:::imm10_1:::(0 as int<1>) as int<21>;
         }

         method set_imm = (int<32> imm) void:
         {
           imm20 = (imm .>> 20) & 1;
           imm10_1 = (imm .>> 19) & 0x3ff;
           imm11 = (imm .>> 10) & 1;
           imm19_12 = (imm .>> 19) & 0xff;
         }
      };

When we create a value of type 'RV32_InsnFmt_J' we can then externally
access the computed field 'imm' like any other normal field.  However,
computed fields are not accessible in other struct methods, functions,
constraint expressions and the like.


File: poke.info,  Node: Struct Attributes,  Prev: Computed Fields,  Up: Structs

20.5.20 Struct Attributes
-------------------------

The following attributes are defined for struct values.

'size'
     Gives an offset with the storage occupied by the complete struct.
     Example:

          (poke) type Packet = struct { byte s; byte[s] d; }
          (poke) (Packet { s = 3 })'size
          32UL#b
'length'
     Gives the number of fields stored in the struct.  Note that, due to
     absent fields, this doesn't always corresponds to the number of
     fields that appear in the definition of a struct type.

     For example, for the following struct type:

          type Packet =
            struct
            {
              byte magic: magic in [0xffUB,0xfeUB];
              byte control if magic == 0xfe;
              byte[128] payload;
            };

     We get the following results:

          (poke) (Packet { magic = 0xff })'length
          2UL
          (poke) (Packet { magic = 0xfe })'length
          3UL
'mapped'
     Boolean indicating whether the struct is mapped.
'strict'
     Boolean indicating whether the struct is mapped in strict mode.
'elem (IDX)'
     Element occupying the position IDX in the array.  Note that this
     attribute evaluates to a value of type 'any'.
'eoffset (IDX)'
     Offset of the field identified by the index IDX in the struct.
     Examples:

          (poke) type Foo = struct { int i; long l; }
          (poke) Foo{}'eoffset (1)
          32#b

     If the provided index is out of bounds then 'E_out_of_bounds' is
     raised.
'esize (IDX)'
     Size of the field identified by the index IDX in the struct.
     Examples:

          (poke) type Foo = struct { int i; long l; }
          (poke) Foo{}'esize (1)
          64#b

     If the provided index is out of bounds then 'E_out_of_bounds' is
     raised.
'ename (IDX)'
     Name of the field identified by the index IDX in the struct.  If
     the field is anonymous then the empty string.

     Examples:

          (poke) type Foo = struct { int foo; long bar; }
          (poke) Foo{}'ename (0)
          "foo"

     If the provided index is out of bounds then 'E_out_of_bounds' is
     raised.


File: poke.info,  Node: Types,  Next: Assignments,  Prev: Structs,  Up: The Poke Language

20.6 Types
==========

* Menu:

* type::			Naming types.
* The any Type::		Polymorphism.
* The isa Operator::		Testing for types of values.
* typeof::                      Introspection of types.


File: poke.info,  Node: type,  Next: The any Type,  Up: Types

20.6.1 'type'
-------------

The 'type' directive allows you to declare named types.  The syntax is:

     type NAME = TYPE [, NAME = TYPE]...;

where NAME is the name of the new type, and TYPE is either a type
specifier or the name of some other type.

   The supported type specifiers are:

'int<N>, uint<N>'
     Integral types.  *Note Integer Types::.
'string'
     The string type.  *Note String Types::.
'TYPE[BOUNDARY]'
     Array types.  *Note Array Types::.
'struct { ... }'
     Struct types.  *Note Struct Types::.
'(TYPE,...)TYPE:'
     Function types.  *Note Function Types::.
'any'
     The 'any' type is used to implement polymorphism.  *Note The any
     Type::.


File: poke.info,  Node: The any Type,  Next: The isa Operator,  Prev: type,  Up: Types

20.6.2 The 'any' Type
---------------------

Poke supports polymorphism with the 'any' type.  This type is used in
contexts where a value of any type is allowed.  For example, this is how
you would declare a function that prints the size of any given value:

     fun print_size = (any value) void:
     {
       printf "%v\n", any'size;
     }

   The rules for handling 'any' values are simple:
   - Everything coerces to 'any'.
   - Nothing coerces from 'any'.

   This means that using any operator that require certain types with
'any' values will fail: you have to cast them first.  Example:

     (poke) fun foo = (any v) int: { return v as int; }

   Arrays of 'any', 'any[]', are also supported:


File: poke.info,  Node: The isa Operator,  Next: typeof,  Prev: The any Type,  Up: Types

20.6.3 The 'isa' Operator
-------------------------

The binary operator 'isa' allows you to check for the type of a given
value:

     (poke) 10 isa int
     1
     (poke) "foo" isa string
     1
     (poke) (Packet  0#B) isa Packet
     1
     (poke) 2 as int<3> isa uint<4>
     0


File: poke.info,  Node: typeof,  Prev: The isa Operator,  Up: Types

20.6.4 'typeof'
---------------

The 'typeof' language construction provides information about some Poke
type.  It has the form:

     typeof (ENTITY)

where ENTITY is either a value or a type specifier.  It returns a
'Pk_Type' value describing either the specified type, or the type of the
specified value.

   The 'Pk_Type' struct provides the following fields for all kind of
types:

'uint<32> code'
     This is a numerical code that identifies the kind of the described
     type.

     Valid codes are 'PK_TYPE_UNKNOWN', 'PK_TYPE_INTEGRAL',
     'PK_TYPE_OFFSET', 'PK_TYPE_STRING', 'PK_TYPE_ARRAY',
     'PK_TYPE_STRUCT', 'PK_TYPE_FUNCTION' and 'PK_TYPE_ANY'.

'string name'
     If the described type is named, then this field contains the name.
     Otherwise it is the empty string.

          (poke) type myint = int
          (poke) typeof (1 as myint)
          Pk_Type {
            code=1,
            name="myint",
            [...]
          }

'int<32> complete_p'
     If the size of the described type can be determined at compile
     time, then this field is 1, 0 otherwise.

   The following fields are provided in 'Pk_Type' only for integral,
offset and integral struct types:

'int<32> signed_p'
     If the described type is signed, this field is 1, 0 otherwise.
'uint<64> size'
     The number of bits of values of the described integral type, or the
     number of bits of the integral value of the described integral
     struct type, or the number of bits of the magnitude of the
     described offset type.

     This would be 23UL for an 'int<23>' type, and 32UL for an
     'offset<int<32>,1>' type.

   The following fields are provided in 'Pk_Type' only for offset types:

'_unit'
     The unit of the described offset type, in bit units.  This would be
     8UL for an 'offset<int<32>,B>' type, for example.

   The following fields are provided in 'Pk_Type' only for array types:

'int<32> bounded_p'
     This field is 1 if the described array type is bounded by either
     number of elements or by size, 0 otherwise.

   The following fields are provided in 'Pk_Type' only for struct types:

'int<32> union_p'
     This field is 1 if the described struct type is an union, 0
     otherwise.
'int<32> pinned_p'
     This field is 1 if the described struct type is pinned, 0
     otherwise.
'int<32> integral_p'
     This field is 1 if the described struct type is integral, 0
     otherwise.
'int<32> nfields'
     Number of fields defined in the described struct type.  This count
     includes optional fields and computed fields.
'int<32> nmethods'
     Number of methods defined in the described struct type.
'string[] fnames'
     Array of 'nfields' strings, with the names of the fields defined in
     the described struct type.  Anonymous fields feature empty strings.
'int<32>[] fcomputed'
     Array of 'nfields' integers, which are 1 for fields that are
     computed, 0 for fields that are not computed.
'string[] ftypes'
     Array of 'nfields' strings, with the type specifiers of the types
     of the fields defined in the described struct type.
'string[] mnames'
     Array of 'nmethods' strings, with the names of the methods defined
     in the described struct type.
'string[] mtypes'
     Array of 'nmethods' strings, with the type specifiers of the types
     of the methods defined in the described struct type.
'(any)any deintegrator'
     Closure that, when passed an integral value of the same signedness
     and width than the described integral struct, returns the struct
     value corresponding to that value.

          (poke) type Foo = struct int<32> { int<16> a; uint<16> b; }
          (poke) typeof (Foo).deintegrator (0x0eadbeef)
          Foo {
            a=0x0eadH,
            b=0xbeefUH
          }

   The following fields are provided in 'Pk_Type' only for struct and
array types:

'(int<32>,int<32>,uint<64>)any mapper'
     Closure that, when passed an integer predicate denoting whether to
     do a strict mapping, an IO space identifier, a bit-offset in the
     given IO space, map a value of the described type.

'(any)void writer'
     Closure that, when passed a mapped value of the described type,
     writes the contents of the value to the corresponding IO space.

'(any)any integrator'
     Closure that, when passed a value of the described type (an array
     type or an integral struct type) returns the integral value
     corresponding to the contents of the value.

          (poke) type Foo = struct int<32> { int<16> a; uint<16> b; }
          (poke) typeof (Foo).integrator (Foo { a = 0xab, b = 0xcd })
          0x00ab00cd

'(any,any)int<32> comparator'
     Closure that, when passed two values of the described type, returns
     1 if the values are equal,0 otherwise.


File: poke.info,  Node: Assignments,  Next: Compound Statements,  Prev: Types,  Up: The Poke Language

20.7 Assignments
================

* Menu:

* Simple Assignments::          Changing the value of variables.
* Bit Assignments::             Bit-concatenation expressions in l-value.


File: poke.info,  Node: Simple Assignments,  Next: Bit Assignments,  Up: Assignments

20.7.1 Simple Assignments
-------------------------

The assignment statement has the form:

     LVALUE = EXP;

where LVALUE is either:

   * A variable.
   * A field reference like 'foo.bar'.
   * An index reference like 'foo[30]'.
   * A map of a type, like 'int @ 0#B' or 'int[3] @ 0#B' or 'Packet @
     12#B'.

   In all cases, the type of EXP should match the type of the referred
entity.

   Examples:

     (poke) foo = 10
     (poke) packet.length = 4
     (poke) packet.data = [1,2,3,4]
     (poke) packet.data[2] = 666
     (poke) int @ 23#B = 23
     (poke) string @ str.offset = "foo"
     (poke) int[2] @ 23#B = [1,2]
     (poke) Packet @ 0#B = Packet { ... }


File: poke.info,  Node: Bit Assignments,  Prev: Simple Assignments,  Up: Assignments

20.7.2 Bit Assignments
----------------------

"Bit assignment" statements have the form:

     BCONC_EXP = EXP

Where BCONC_EXP is an expression composed by bit-concatenation operators
and operands that should be valid l-values themselves, and EXP is an
expression whose type must be integral and whose width must correspond
exactly to the width of the integral type of BCONC_EXP.

   For example, consider this code:

     var a = 0UH;
     var b = 0UH;

     a:::b = 0xbeef;

   The assignment above updates the value of the variable 'a' to be
'0xbeUH' and the value of the variable 'b' to be '0xefUH'.  Note how the
signedness of BCONC_EXP and EXP may differ.

   Any valid l-value can be used as an operand of the bit-concatenation
operators in BCONC_EXP.  For example:

     var a = [0UH,0UH];

     a[0]:::a[1] = 0xbeef;

or, using struct fields:

     type Foo = struct { uint<16> hi; uint<16> lo; };

     var f = Foo {};
     f.hi:::f.lo = 0xbeef;


File: poke.info,  Node: Compound Statements,  Next: Conditionals,  Prev: Assignments,  Up: The Poke Language

20.8 Compound Statements
========================

Compound statements have the form

     { STMT... }

where STMT... is a list of statements, which can be themselves compound
statements.  Compound statements are primarily used to sequence
instructions like:

     {
       do_a;
       do_b;
       do_c;
     }

   A compound statement introduces a new lexical scope.  Declarations in
the compound statements are local to that statement.

   Finally, compound statements can be empty: '{ }'.


File: poke.info,  Node: Conditionals,  Next: Loops,  Prev: Compound Statements,  Up: The Poke Language

20.9 Conditionals
=================

Poke provides several conditional statements, and a ternary conditional
operator, which are discussed in the sections below.

* Menu:

* if-else::			Simple conditionals.
* Conditional Expression::	Conditionals in expressions.


File: poke.info,  Node: if-else,  Next: Conditional Expression,  Up: Conditionals

20.9.1 'if-else'
----------------

The 'if-else' statement has the form

     if (EXP) IF_STMT [else ELSE_STMT]

where EXP is an expression that should evaluate to a boolean value (i.e.
to an integer), IF_STMT is a statement that will be executed if EXP
holds true, and ELSE_STMT is a statement that will be executed if EXP
holds false.  The 'else' part of the statement is optional.


File: poke.info,  Node: Conditional Expression,  Prev: if-else,  Up: Conditionals

20.9.2 Conditional Expressions
------------------------------

Poke supports a ternary conditional expression that has the form:

     CONDITION ? TRUE_EXPRESSION : FALSE_EXPRESSION

where CONDITION is an expression that should evaluate to a boolean, and
TRUE_EXPRESSION and FALSE_EXPRESSION are expressions that have exactly
the same type.


File: poke.info,  Node: Loops,  Next: Expression Statements,  Prev: Conditionals,  Up: The Poke Language

20.10 Loops
===========

Poke supports several iteration statements, which are discussed in the
sections below.

* Menu:

* while::		Iterate while a condition holds true.
* for::                 Generalized loop statement.
* for-in::		Iterate over the elements of a container.


File: poke.info,  Node: while,  Next: for,  Up: Loops

20.10.1 'while'
---------------

The 'while' statement has this form:

     while (EXP) STMT

where EXP is an expression that should evaluate to a boolean (i.e.  to
an integer) and STMT is an statement that will be executed until EXP
holds false.

   It is possible to leave the loop from within STMT using the 'break'
statement.  Example:

     while (1)
     {
       [...]
       if (exit_loop)
         break;
     }

   It is also possible to jump to the next iteration of the loop from
within STMT using the 'continue' statement.  Example:

     while (1)
     {
        [...]
        if (continue_loop)
          continue;
     }


File: poke.info,  Node: for,  Next: for-in,  Prev: while,  Up: Loops

20.10.2 'for'
-------------

The 'for' statement has this form:

     for ([DECLS];[EXPR];[STMTS]) STMT

where DECLS is an optional declaration or chain of declarations
separated by commas, EXPR is an optional boolean expression, STMTS is an
optional comma-separated list of statements, and STMT is a statement.


File: poke.info,  Node: for-in,  Prev: for,  Up: Loops

20.10.3 'for-in'
----------------

The 'for-in' statement has this form:

     for (FORMAL in CONTAINER [where EXP]) STMT

where, in each iteration, the name FORMAL will be associated with
consecutive values of CONTAINER, which shall be an expression evaluating
to an array or a string.  FORMAL is available in STMT, which is the
statement executed in each iteration.

   If the WHERE part is specified, then only iteration in which EXP
holds true are processed.  FORMAL can be referred in EXP.  Note that
this doesn't mean the loop will stop after processing the first "not
selected" element.  See the following example:

     (poke) for (c in [1,2,3,4] where c % 2) printf " %v", c
      1 3

   It is possible to leave the loop from within STMT using the 'break'
statement.

   It is also possible to jump to the next iteration of the loop from
within STMT using the 'continue' statement.


File: poke.info,  Node: Expression Statements,  Next: Functions,  Prev: Loops,  Up: The Poke Language

20.11 Expression Statements
===========================

Poke is one of these languages where there is a clear separation between
"expressions" and "statements".  However, it is often useful to use an
expression in the place of an statement, in order to benefit from its
side effects.

   For that purpose Poke allows you to expressions as statements using
the following syntax:

     EXP;

   The value computed by the expression will be discarded.


File: poke.info,  Node: Functions,  Next: Assembler,  Prev: Expression Statements,  Up: The Poke Language

20.12 Functions
===============

* Menu:

* Function Declarations::	Writing functions.
* Optional Arguments::		Default values for arguments.
* Variadic Functions::		Functions taking any number of arguments.
* Calling Functions::		Invoking functions.
* Function Types::		Useful for defining interfaces.
* Lambdas::                     Functions in expressions.
* Function Comparison::         Comparing function values.
* Function Attributes::         Accessing properties of function values.


File: poke.info,  Node: Function Declarations,  Next: Optional Arguments,  Up: Functions

20.12.1 Function Declarations
-----------------------------

A function is declared using the following syntax:

     fun NAME = [(FORMAL,...)] RET_TYPE:
     {
        ... body ...
     }

where NAME is the name of the function, which uses the same namespace as
variables and types and RET_TYPE is the type of the value returned by
the function.  If the function returns no value then it is 'void'.

   Each FORMAL argument has the form:

     TYPE NAME [= EXP]

where TYPE is the type of the formal, NAME its name, and EXP is an
optional expression that will be used to initialize the argument in case
it is not specified when the function is called.

   The last formal argument can take the form 'NAME...', meaning the
function is variadic.  *Note Variadic Functions::.

   If the function takes no arguments, it is possible to omit the list
of arguments entirely:

     fun hello = void: { print "Hello!\n"; }

   The 'return' statement is used to return values in functions that
return a value.  Example:

     fun gcd = (uint<64> a, uint<64> b) uint<64>:
       {
        if (b == 0)
          return a;
        else
          return gcd (b, a % b);
       }

   Note that reaching the end of a non-void function will trigger a
run-time error.


File: poke.info,  Node: Optional Arguments,  Next: Variadic Functions,  Prev: Function Declarations,  Up: Functions

20.12.2 Optional Arguments
--------------------------

Optional function arguments are specified like:

     fun atoi = (string s, int b = 10) long: { ... }

   Which means that if the base argument is not specified when passed to
'atoi' then it is initialized to 10.

   Optional arguments should not appear before any non-optional argument
in function declarations.  The following is not valid Poke:

     fun foo = (int i = 10, int j) int: { return i + j; }

   Note that arguments declared before an optional argument can be used
in its initialization expression.  This is valid Poke:

     fun foo = (int n, int[n] array = init_array (n)) void: { ... }


File: poke.info,  Node: Variadic Functions,  Next: Calling Functions,  Prev: Optional Arguments,  Up: Functions

20.12.3 Variadic Functions
--------------------------

Functions getting an arbitrary number of arguments are denoted like
this:

     fun printf (string fmt, args...) void: { ... }

   The variadic argument shall be the last argument in the function, and
it is of type 'any[]'.


File: poke.info,  Node: Calling Functions,  Next: Function Types,  Prev: Variadic Functions,  Up: Functions

20.12.4 Calling Functions
-------------------------

To call a function, write its name followed by the arguments in
parentheses.  Examples:

     foo (1,2,3)
     bar ()

   If the function takes no arguments then it is not necessary to write
the empty list of arguments.  Therefore the following two calls are
equivalent:

     bar ()
     bar

   If the closure of function that takes no arguments is needed, the
call can be avoided by putting the variable immediately inside
parenthesis, like this:

     (poke) (foo)
     #<closure>

   There is an alternate syntax that can be used in both expressions and
expression-statements.  This alternate syntax is:

     FUNCTION_NAME :ARG1 VAL1...

where ARG1 is the name of an argument and VAL1 the value to pass for
that argument.  This is useful when using functions as commands in the
REPL:

     (poke) dump :from 12#B :size 16#B :ascii 0

   Note that the named arguments can appear in any order.  The following
two calls are equivalent:

     dump :from 12#B :size 16#B
     dump :size 16#B :from 12#B

   If this alternate syntax for function calls is to be used in an
expression, it is necessary to surround it with parenthesis:

     2 + (gcd :a 1024 :b 8)


File: poke.info,  Node: Function Types,  Next: Lambdas,  Prev: Calling Functions,  Up: Functions

20.12.5 Function Types
----------------------

Function types are denoted like:

     (TYPE,...)RET_TYPE:

where TYPE are the types of the arguments and RET_TYPE is the type of
the value returned by the function.

   Optional arguments are marked with a '?' after the type.  For
example, the type of the 'atoi' function with declaration:

     fun atoi = (string s, int b = 10) long: { ... }

is '(string,int?)long:'.

   If the function has variadic arguments, the position of the variadic
argument in the function type specifier contains '...'.  For example,
the type of a 'printf' function with declaration:

     fun printf (string fmt, args...) void: { ... }

is '(string,...)void:'.


File: poke.info,  Node: Lambdas,  Next: Function Comparison,  Prev: Function Types,  Up: Functions

20.12.6 Lambdas
---------------

Poke support "lambda expressions" using the following syntax:

     lambda FUNCTION_SPECIFIER

Where FUNCTION_SPECIFIER is any function specifier.  Examples:

     lambda void: {}
     lambda (int i) int: { return i * 2; }

Lambdas can be manipulated exactly like any other Poke value, and can be
stored in variables.  Therefore, this is an alternative way of defining
a named function (which can't be recursive for obvious reasons):

     var double = lambda (int i) int: { return i * 2 };


File: poke.info,  Node: Function Comparison,  Next: Function Attributes,  Prev: Lambdas,  Up: Functions

20.12.7 Function Comparison
---------------------------

The equality operator ('==') and the inequality operator ('!=') can be
applied to functions.  They evaluate to true if the operands are the
same function value.  Examples:

     (poke) lambda void: {} == lambda void: {}
     0
     (poke) lambda void: {} != lambda void: {}
     1
     (poke) var f = void: {}
     (poke) f == f
     1
     (poke) f != f
     0


File: poke.info,  Node: Function Attributes,  Prev: Function Comparison,  Up: Functions

20.12.8 Function Attributes
---------------------------

The following attributes are defined for function values.

'size'
     Gives an offset '0#B', by convention.


File: poke.info,  Node: Assembler,  Next: Endianness,  Prev: Functions,  Up: The Poke Language

20.13 Assembler
===============

Poke provides two ways to execute PVM assembler instructions: an 'asm'
expression and an 'asm' statement.

"asm statements" take the following form:

     asm (TEMPLATE [: OUTPUTS [: INPUTS]])

where TEMPLATE is the written form of a PVM assembler program, OUTPUTS a
comma separated list of l-values ans INPUTS a comma separated list of
expressions.

   Before the assembler program in TEMPLATE is executed, the INPUTS (if
any) are pushed on the stack.  After the assembler program is executed,
it is expected to have left the same number of elements on the stack
than OUTPUTS specified.  These values are then assigned to the outputs,
in reverse order.

   Example:

     var result = 0;
     asm ("addi; nip2" : result : 10, 20);

After the execution of the 'asm' statement above, the value 30 is stored
in the variable 'result'.

"asm expressions" take the form:

     asm TYPE: (TEMPLATE [: INPUTS])

where TYPE is a simple type specifier and TEMPLATE and INPUTS have the
same meaning than in 'asm' statements.  A single output is always
expected to be generated on the stack, of type TYPE.

   Example:

     (poke) asm int: ("addi; nip2" : 10, 20) + 2
     32

   In both 'asm' statements and expressions the compiler generates code
that tries to determine whether the execution of the assembler code
results in the original stack being underflown or overflown.  If this is
found to happen an exception 'E_stack' is raised.

   'E_stack' is also raised in case an 'asm' statement or expression
leaves a non-representable PVM value as an output.  This is for example
the case of 'PVM_NULL', which can't be represented in Poke.

   Note however that the above mentioned tests are not perfect, and it
is generally possible to crash the system using 'asm' statements or
expressions.


File: poke.info,  Node: Endianness,  Next: Mapping,  Prev: Assembler,  Up: The Poke Language

20.14 Endianness
================

Byte endianness is an important aspect of encoding data.  As a good
binary editor poke provides support for both little and big endian, and
will soon acquire the ability to encode exotic endianness like PDP
endian.  Endianness control is integrated in the Poke language, and is
designed to be easily used in type descriptions.

* Menu:

* set endian::			dot-command to get and set the endianness.
* Endian in Fields::		setting the endianness of struct fields.
* Endian built-ins::		changing endianness programmatically.


File: poke.info,  Node: set endian,  Next: Endian in Fields,  Up: Endianness

20.14.1 '.set endian'
---------------------

GNU poke maintains a global variable that holds the current endianness.
This is the endianness that will be used when mapping integers whose
types do not specify an explicit endianness.

   Like other poke global state, this global variable can be modified
using the '.set' dot-command:

     .set endian little
     .set endian big
     .set endian host

The current endianness can be obtained like this:

     (poke) .set endian
     little

   We can easily see how changing the current endianness indeed impacts
the way integers are mapped:

     (poke) dump :from 0#B :size 4#B :ruler 0 :ascii 0
     00000000: 8845 4c46
     (poke) .set endian little
     (poke) int @ 0#B
     0x464c4588
     (poke) .set endian big
     (poke) int @ 0#B
     0x88454c46


File: poke.info,  Node: Endian in Fields,  Next: Endian built-ins,  Prev: set endian,  Up: Endianness

20.14.2 Endian in Fields
------------------------

It is possible to set the endianness of integral fields in struct type
descriptors.  *Note Field Endianness::.


File: poke.info,  Node: Endian built-ins,  Prev: Endian in Fields,  Up: Endianness

20.14.3 Endian built-ins
------------------------

As handy as the '.set endian' dot-command may be, it is also important
to be able to change the current endianness programmatically from a Poke
program.  For that purpose, the PKL compiler provides a couple of
built-in functions: 'get_endian' and 'set_endian'.

   Their definitions, along with the specific supported values, look
like:

     var ENDIAN_LITTLE = 0;
     var ENDIAN_BIG = 1;

     fun get_endian = int: { ... }
     fun set_endian = (int endian) int: { ... }

   Accessing the current endianness programmatically is especially
useful in situations where the data being poked features a different
structure, depending on the endianness.

   A good (or bad) example of this is the way registers are encoded in
eBPF instructions.  eBPF is the in-kernel virtual machine of Linux, and
features an ISA with ten general-purpose registers.  eBPF instructions
generally use two registers, namely the source register and the
destination register.  Each register is encoded using 4 bits, and the
fields encoding registers are consecutive in the instructions.

   Typical.  However, for reasons we won't be discussing here the order
of the source and destination register fields is switched depending on
the endianness.

In big-endian systems the order is:

     dst:4 src:4

Whereas in little-endian systems the order is:

     src:4 dst:4

   In Poke, the obvious way of representing data whose structure depends
on some condition is using an union.  In this case, it could read like
this:

     type BPF_Insn_Regs =
       union
       {
         struct
         {
           BPF_Reg src;
           BPF_Reg dst;
         } le : get_endian == ENDIAN_LITTLE;

         struct
         {
           BPF_Reg dst;
           BPF_Reg src;
         } be;
       };

   Note the call to the 'get_endian' function (which takes no arguments
and thus can be called Algol68-style, without specifying an empty
argument list) in the constraint of the union alternative.  This way,
the register fields will have the right order corresponding to the
current endianness.

   Nifty.  However, there is an ever better way to denote the structure
of these fields.  This is it:

     type BPF_Insn_Regs =
       struct
       {
         var little_p = (get_endian == ENDIAN_LITTLE);

         BPF_Reg src @ !little_p * 4#b;
         BPF_Reg dst @ little_p * 4#b;
       };

   This version, where the ordering of the fields is implemented using
field labels, is not only more compact, but also has the virtue of not
requiring additional "intermediate" fields like 'le' and 'be' above.  It
also shows how convenient can be to declare variables inside structs.

Let's see it in action:

     (poke) BPF_Insn_Regs @ 1#B
     BPF_Insn_Regs {src=#<%r4>,dst=#<%r5>}
     (poke) .set endian big
     (poke) BPF_Insn_Regs @ 1#B
     BPF_Insn_Regs {src=#<%r5>,dst=#<%r4>}

   Changing the current endianness in constraint expressions is useful
when dealing with binary formats that specify the endianness of the data
that follows using some sort of tag.  This is the case of ELF, for
example.  The first few bytes in an ELF header conform what is known as
the 'e_ident'.  One of these bytes is called 'ei_data' and its value
specifies the endianness of the data stored in the ELF file.

This is how we handle this in Poke:

     fun elf_endian = (int endian) byte:
      {
        if (endian == ENDIAN_LITTLE)
          return ELFDATA2LSB;
        else
          return ELFDAT2MSB;
      }

     [...]

     type Elf64_Ehdr =
       struct
       {
         struct
         {
           byte[4] ei_mag : ei_mag[0] == 0x7fUB
                            && ei_mag[1] == 'E'
                            && ei_mag[2] == 'L'
                            && ei_mag[3] == 'F';
           byte ei_class;
           byte ei_data : (ei_data != ELFDATANONE
                           && set_endian (elf_endian (ei_data)));
           byte ei_version;
           byte ei_osabi;
           byte ei_abiversion;
           byte[6] ei_pad;
           offset<byte,B> ei_nident;
         } e_ident;

         [...]
       };

   Note how 'set_endian' returns an integer value... it is always '1'.
This is to facilitate its usage in field constraint expressions.


File: poke.info,  Node: Mapping,  Next: Exception Handling,  Prev: Endianness,  Up: The Poke Language

20.15 Mapping
=============

The purpose of poke is to edit "IO spaces", which are the files or
devices, or memory areas being edited.  This is achieved by mapping
values.  Mapping is perhaps the most important concept in Poke.

* Menu:

* IO Spaces::			The underlying entities being edited.
* The Map Operator::		The @ operator.
* Mapping Simple Types::	Mapping integers, offsets and strings.
* Mapping Structs::		Mapping collections of fields.
* Mapping Arrays::		Mapping sequences of things.
* Mapping Functions::           Orthogonality is important.
* Non-strict Mapping::          Working with incorrect data.
* Auto-Remapping::              Switching to explicit remaps.
* Unmapping::			From mapped values to regular values.


File: poke.info,  Node: IO Spaces,  Next: The Map Operator,  Up: Mapping

20.15.1 IO Spaces
-----------------

GNU poke supports the abstract notion of "IO space", which is an
addressable space of Poke objects: integers, strings, arrays, structs,
etc.  This underlying storage for the IO spaces (which we call "IO
devices") can be heterogeneous: from a file your file system to the
memory of some process.

* Menu:

* open::			Creating IO spaces.
* opensub::                     IO sub spaces.
* openproc::                    IO proc spaces.
* close::			Destroying IO spaces.
* flush::			Flushing IO spaces.
* get_ios::			Getting the current IO space.
* set_ios::			Setting the current IO space.
* iolist::                      Getting a list of open IO spaces.
* openset::                     Opening and setting combined.
* iosize::			Getting the size of an IO space.
* iohandler::                   Getting the handler string of an IO space.
* ioflags::                     Getting the flags of an IO space.
* IO Space Hooks::              Hooking in common operations on IO spaces.


File: poke.info,  Node: open,  Next: opensub,  Up: IO Spaces

20.15.1.1 'open'
................

The 'open' builtin allows you to create new IO spaces, by opening an IO
device.  It has the following prototype:

     fun open = (string HANDLER, uint<64> flags = 0) int<32>

where HANDLER is a string identifying the IO device that will serve the
IO space.  This handler can be:

'*NAME*'
     An auto growing memory buffer.
'pid://[0-9]+'
     The process ID of some process.
'/path/to/file'
     An either absolute or relative path to a file.
'nbd://HOST:PORT/EXPORT'
'nbd+unix:///EXPORT?socket=/PATH/TO/SOCKET'
     A connection to an NBD server.  *Note nbd command::

   FLAGS is a bitmask that specifies several aspects of the operation,
including the mode in which the IO space is opened.  Its value is
usually built by ORing a set of flags that are provided by the compiler.
These are:

'IOS_F_READ'
     The IO space is intended to be read.
'IOS_F_WRITE'
     The IO space is intended to be written.
'IOS_F_CREATE'
     If the IO device doesn't exist, then create it, usually empty.

Note that the specific behaviour of these flags depend on the nature of
the IO space that is opened.  For example a memory buffer is always
truncated at creation by default.

   In order to ease the usage of 'open', a few pre-made bitmaps are
provided to specify opening "modes":

'IOS_M_RDONLY'
     This is equivalent to 'IOS_F_READ'.
'IOS_M_WRONLY'
     This is equivalent to 'IOS_F_WRITE'.
'IOS_M_RDWR'
     This is equivalent to 'IOS_F_READ | IOS_F_WRITE'.

   The 'open' builtin returns a signed 32-bit integer.  This number will
identify the just opened IOS until it gets closed.

   If there is a problem opening the specified IO device then 'open'
will raise an 'E_no_ios' exception.


File: poke.info,  Node: opensub,  Next: openproc,  Prev: open,  Up: IO Spaces

20.15.1.2 'opensub'
...................

The 'opensub' standard function allows you to create IO spaces that show
a sub-region of some other IO space.  The prototype is:

     fun opensub = (int<32> IOS,
                    offset<uint<64>,B> BASE, offset<uint<64>,B> SIZE,
                    string NAME = "",
                    uint<64> FLAGS = 0) int<32>

where IOS is the ID of the base IOS, BASE is the offset in IOS where the
sub-range starts and SIZE is the size of the range.

   The argument NAME is a descriptive name of the contents of the range,
and it is empty by default.

   The argument FLAGS is an ORed value of 'IOS_F_*' flags.  If no
explicit FLAGS are specified then the sub space inherits the flags of
the underlying base IOS. If explicit FLAGS are provided and they
contradict the flags of the underlying IOS then 'E_ios_flags' is raised.

   Trying to access a sub space whose base IOS has been closed results
in a 'E_io' exception.


File: poke.info,  Node: openproc,  Next: close,  Prev: opensub,  Up: IO Spaces

20.15.1.3 'openproc'
....................

The 'openproc' standard function allows you to create IO spaces to
access the memory of some running program, given its process ID. The
prototype is:

     fun openproc = (uint<64> PID, uint<64> FLAGS = 0) int<32>

where PID is the process ID whose memory we want to poke and FLAGS is a
set of open flags.


File: poke.info,  Node: close,  Next: flush,  Prev: openproc,  Up: IO Spaces

20.15.1.4 'close'
.................

The 'close' builtin allows you to destroy IO spaces, closing the
underlying IO device.  The prototype is:

     fun close = (int<32> IOS) void

where IOS is some previously created IO space.  All pending data is
written to the underlying IO device.

   If the IO space specified to 'close' doesn't exist then an 'E_no_ios'
exception is raised.

   If errors occurred while closing the IO space, then 'E_ios' exception
is raised.


File: poke.info,  Node: flush,  Next: get_ios,  Prev: close,  Up: IO Spaces

20.15.1.5 'flush'
.................

The builtin 'flush' performs a "flushing" operation on a given IO space.
The prototype is:

     fun flush = (int<32> IOS, offset<uint<64>,1> OFFSET) void

   Where IOS is the IOS identifier where to perform the flush.  The
semantics associated with the "flushing" operation depends on the kind
of IO space:

   * Read-only stream IOS will discard already mapped input up to
     OFFSET.  Any further attempt of mapping data at that area will
     cause an E_EOF exception (for Early Of File ;)).
   * Flushing is a no-operation for other kind of IO spaces.


File: poke.info,  Node: get_ios,  Next: set_ios,  Prev: flush,  Up: IO Spaces

20.15.1.6 'get_ios'
...................

GNU poke maintains a "current IO space", which is the last created IO
space (this includes IO spaces opened and selected using a dot-command).
The builtin 'get_ios' returns this space.  It has the following
prototype:

     fun get_ios = int<32>

   If there is no IO space, 'get_ios' will raise the 'E_no_ios'
exception.


File: poke.info,  Node: set_ios,  Next: iolist,  Prev: get_ios,  Up: IO Spaces

20.15.1.7 'set_ios'
...................

The 'set_ios' builtin allows you to set a specific IO space as the new
current IO space.  It has the following prototype:

     fun set_ios = (int<32> IOS) int<32>

where IOS is the IO space that will become the current IO space.  If the
IO space specified to 'set_ios' doesn't exist, 'E_no_ios' will be
raised.

   Note that 'set_ios' always returns '1'.  This is to ease its usage in
struct fields constraint expressions.


File: poke.info,  Node: iolist,  Next: openset,  Prev: set_ios,  Up: IO Spaces

20.15.1.8 'iolist'
..................

At any time there are zero or more open IO spaces.  The 'iolist' builtin
returns an array of identifiers of these IO spaces.  It has the
following prototype:

     fun iolist = int<32>[]

If no IO space is currently open then 'iolist' returns the empty array.
The ordering of the IO spaces in the array is arbitrary.


File: poke.info,  Node: openset,  Next: iosize,  Prev: iolist,  Up: IO Spaces

20.15.1.9 'openset'
...................

Generally when an IO space is opened with 'open' it won't automatically
become the current IO space; it will only happens if there wasn't an IO
space previously open.

   The standard function 'openset' is like 'open' that always sets the
opened IO space as the new current space.  It has the following
prototype:

     fun openset = (string HANDLER, uint<64> FLAGS = 0) int<32>

Where the meaning of HANDLER, FLAGS and the returned value are exactly
like in 'open'.


File: poke.info,  Node: iosize,  Next: iohandler,  Prev: openset,  Up: IO Spaces

20.15.1.10 'iosize'
...................

The 'iosize' builtin returns the size of a given IO space, as an offset.
It has the following prototype:

     fun iosize = (int<32> ios = get_ios) offset<uint<64>,1>

   If the IO space specified to 'iosize' doesn't exist, 'E_no_ios' will
be raised.


File: poke.info,  Node: iohandler,  Next: ioflags,  Prev: iosize,  Up: IO Spaces

20.15.1.11 'iohandler'
......................

The 'iohandler' builtin returns the handler string of some given IO
space.  It has the following prototype:

     fun iohandler = (int<32> ios = get_ios) string

   If the IO space specified to 'iohandler' doesn't exist, 'E_no_ios'
will be raised.


File: poke.info,  Node: ioflags,  Next: IO Space Hooks,  Prev: iohandler,  Up: IO Spaces

20.15.1.12 'ioflags'
....................

The 'ioflags' builtin returns the flags active in a given IO space,
encoded in an unsigned 64-bit integer.  It has the following prototype:

     fun ioflags = (int<32> ios = get_ios) uint<64>

   If the IO space specified to 'ioflags' doesn't exist, 'E_no_ios' will
be raised.


File: poke.info,  Node: IO Space Hooks,  Prev: ioflags,  Up: IO Spaces

20.15.1.13 IO Space Hooks
.........................

The user can hook in the IO subsystem by installing functions that will
be invoked when certain operations on IO spaces are being performed.

   The functions in 'ios_open_hook' are invoked once a new IO space has
been opened.

   The functions in 'ios_close_pre_hook' are invoked when an IO space is
about to be closed.  Note that a close_pre hook can prevent the closing
operation to be performed by raising an exception.

   The functions in 'ios_close_hook' are invoked when an IO space has
been closed.

   The functions in 'ios_set_hook' are invoked when an IO space becomes
the current IO space.

   All the hooks above get the id of an IO space as arguments:

     type IOS_Hook_Fn = (int<32>)void

   The different 'io*' built-ins can be then used by the handlers in
order to fetch additional properties of the IO space.  For example:

     fun my_open_handler = (int<32> ios) void:
     {
       printf ("*** The IO space '%s' (%i32d) has been opened.\n",
               iohandler (ios), ios);
     }

     type IOS_Hook_Close_Fn = (int<32>)void;


File: poke.info,  Node: The Map Operator,  Next: Mapping Simple Types,  Prev: IO Spaces,  Up: Mapping

20.15.2 The Map Operator
------------------------

Poke values reside in memory, and their in-memory representation is not
visible from Poke programs.  For example, '32' is a 32-bit signed
integer value, and it happens to not be boxed in the Poke Virtual
Machine.  Therefore, it occupies exactly 32-bit in the memory of the
machine running poke.  Other values, like arrays for example, are boxed,
and they need to store various meta-data.

   Regardless of the internal representation, we say these values live
"in memory".  Now, it is also possible to "map" a value to some area in
some underlying IO space.  This is done with the map operator '@', which
has two alternate syntax:

     TYPE @ OFFSET
     TYPE @ IOS : OFFSET

   The ternary version creates a new value using the data located at the
offset OFFSET in the specified IO space IOS, which shall be an
expression evaluating to a signed 32-bit integer.

   The binary version uses the current IO space.

   If there is no IO space, or the specified IO space doesn't exist, an
'E_no_ios' exception is raised:

     (poke) int @ 0#B
     unhandled no IOS exception

   The value created in a map can be either mapped or not mapped.
Mapping simple types produces not mapped values, whereas mapping
non-simple types create mapped values.

   The value attributes 'mapped' and 'offset' can be used to check
whether a value is mapped or not, and in that case the offset where it
is mapped:

     (poke) var p = Packet @ 0#B
     (poke) p'mapped
     0x1
     (poke) p'offset
     0x0UL#b

   Using the 'offset' attribute in a not mapped value results in the
'E_no_map' exception being raised:

     (poke) [1,2,3]'mapped
     0x0
     (poke) [1,2,3]'offset
     unhandled no map exception

   If the type specified in the map is not a simple type, like an array
or a struct, the resulting value is said to be mapped in the IO space:

     (poke) type Packet = struct { int i; long l; }
     (poke) Packet @ 0#B
     Packet {i=0x464c457f,l=0x10102L}
     (poke) uint<8>[2] @ 0#B
     [0x7fUB,0x45UB]

   A very important idea on Poke mapping is that it should be possible
to manipulate mapped and non-mapped values in a transparent way.  For
example, consider the quick sort implementation in poke's standard
library.  The prototype is:

     fun qsort = (any[] array, Comparator cmp_f,
                    long left = 0, long right = array'length - 1) void

'qsort' works with both mapped and not-mapped arrays:

     (poke) var a = [2,3,1]
     (poke) var b = int[3] @ 0#B
     (poke) b
     [1179403647,65794,0]
     (poke) qsort (a, IntComparator)
     (poke) a
     [1,2,3]
     (poke) qsort (b, IntComparator)
     (poke) b
     [0,33620224,1179403647]
     (poke) dump :from b'offset :size b'size :ascii 0
     76543210  0011 2233 4455 6677 8899 aabb ccdd eeff
     00000000: 0000 0000 0001 0102 7f45 4c46

   Similarly, you can write functions that operate on abstract entities
and data structures such as ELF relocations and sections, DWARF DIEs,
etc, and the same code will work with non mapped and mapped values.


File: poke.info,  Node: Mapping Simple Types,  Next: Mapping Structs,  Prev: The Map Operator,  Up: Mapping

20.15.3 Mapping Simple Types
----------------------------

Simple values (i.e.  integers, offsets, strings) cannot be mapped.
Therefore, if the type specified in the map is a simple type, the
resulting value will be a regular non-mapped value.  Examples:

     (poke) uint<8> @ 0#B
     0x7fUB
     (poke) string @ 0#B
     "ELF"


File: poke.info,  Node: Mapping Structs,  Next: Mapping Arrays,  Prev: Mapping Simple Types,  Up: Mapping

20.15.4 Mapping Structs
-----------------------

Struct and union types can be referred by name in a mapping ('@')
operation.  For example, given a struct type 'Foo' defined as:

     type Foo =
       struct
       {
         int i;
         long l;
       }

we could get a mapped struct value of that type like this:

     var f = Foo @ 128#B;


File: poke.info,  Node: Mapping Arrays,  Next: Mapping Functions,  Prev: Mapping Structs,  Up: Mapping

20.15.5 Mapping Arrays
----------------------

Arrays can be mapped in IO space in three different ways, depending on
the characteristics of the type provided to the mapping operator.

* Menu:

* Array maps bounded by number of elements::
* Array maps bounded by size::
* Unbounded array maps::
* Mapped bounds in bounded arrays::


File: poke.info,  Node: Array maps bounded by number of elements,  Next: Array maps bounded by size,  Up: Mapping Arrays

20.15.5.1 Array maps bounded by number of elements
..................................................

When an array type bounded by number of elements is used in a mapping
operation, the resulting mapped array is also bounded by number of
elements.

   For example, this is how we would map an array of four 32-bit signed
integers in the current IO space:

     (poke) int[4] @ 0#B
     [10,20,30,40]

   Since you can also provide a dynamic array type to the map operator,
the number of elements doesn't need to be constant.  For example, given
the variable 'nelems' has a value of '2':

     (poke) var nelems = 2
     (poke) int[nelems + 1] @ 0#B
     [100,222,333]

   If for whatever reason the exact requested number of elements can't
be mapped, then 'E_constraint' is raised.

   If an end-of-file condition happens while mapping the array, because
the number of elements specified in the array type, at the given offset,
exceeds the capacity of the underlying IO device, an exception is raised
and the mapping is not completed:

     (poke) int[99999999999] @ 0#B
     unhandled EOF exception

   Likewise, if a constraint fails while performing the mapping (while
mapping an array of structs, for example) an exception is raised and the
map is aborted.


File: poke.info,  Node: Array maps bounded by size,  Next: Unbounded array maps,  Prev: Array maps bounded by number of elements,  Up: Mapping Arrays

20.15.5.2 Array maps bounded by size
....................................

While dealing with binary formats, it often happens that the number of
entities in a collection is given by the space they occupy, rather than
the count itself.

   For example, consider ELF sections holding relocations.  These
sections contain a collection of zero or more relocations.  The layout
of each relocation is specified by the following type:

     type Elf64_Rela =
       struct
       {
         offset<Elf64_Addr,B> r_offset;
         Elf64_Xword r_info;
         Elf64_Sxword r_addend;
       };

   The section is described by an entry in the ELF sections header
table:

     type Elf64_Shdr =
       struct
       {
         Elf_Word sh_name;
         Elf_Word sh_type;
         Elf64_Xword sh_flags;
         Elf64_Addr sh_addr;
         Elf64_Off sh_offset;
         offset<Elf64_Xword,B> sh_size;
         Elf_Word sh_link;
         Elf_Word sh_info;
         Elf64_Xword sh_addralign;
         offset<Elf64_Xword,b> sh_entsize;
       };

   The relevant elements of 'Elf64_Shdr' are 'sh_offset' and 'sh_size',
which indicate the offset of the beginning of the section's contents,
and its size, respectively.  At this point, if we wanted to get an array
with all the relocations in the section, we could map an array bounded
by number of elements like we saw in the previous section, like this:

     (poke) Elf64_Rela[sh_size / 1#Elf64_Rela]
     [... relocs ...]

   However, this approach adoleces from two problems.  First, it doesn't
work with any entity type.  For an offset like '1#Elf64_Rela' to work,
it is required to know the size of the type specified as the unit at
compile time.  In the particular case of 'Elf64_Rela', that condition is
satisfied, but too often that's not the case.  For example, think about
a section containing 'NULL' terminated strings: you can't know the
number of strings contained in the section until you actually read it.

   Another problem is when the data in the header is corrupt.  Using the
mapping bounded by number of elements, we wouldn't realize it.  It would
be good if the tool would tell us whether the specified size actually
holds an exact number of the requested elements.

   A mapping bound by size is what we need.  Fortunately, as we saw when
discussing array types, Poke allows you to specify an offset instead of
an integral value, in the array type specification.  The right amount of
entities (in this case relocations) to strictly satisfy the provided
size will be mapped in the IO space.  So, in order to obtain an array
containing all the relocations in the section, we simply write:

     (poke) Elf64_Rela[ehdr.sh_size] @ ehdr.sh_offset
     [... relocs ...]

   The strictness mentioned above is important.  GNU poke will complain
(and abort the mapping) if it is not possible to map an exact number of
elements.  Thus the following mapping would not be successful:

     (poke) int[33#b] @ 0#B
     unhandled out of map bounds exception

   Like in mappings bounded by number of elements, if a constraint fails
while performing the mapping, an exception is raised and the map is
aborted.

   Likewise, if the exact size specified as the array boundaries can't
be achieved, then 'E_constraint' is raised.


File: poke.info,  Node: Unbounded array maps,  Next: Mapped bounds in bounded arrays,  Prev: Array maps bounded by size,  Up: Mapping Arrays

20.15.5.3 Unbounded array maps
..............................

We mentioned above that if an end-of-file condition happens while
performing a mapping (be it bounded by number of elements or bounded by
size) an EOF exception is raised, and the mapping operation is aborted.

   Unbounded array mappings are performed by using an unbounded array
type in the mapping operation, like in:

     TYPE[] @ 0#B

   The above construction will map values of type TYPE in the IO space
until there is an end-of-file condition, or a constraint fails, whatever
happens first.  When it is a constraint expression that fails, that last
element is not included in the mapped array.

   Let's assume a binary file contains a series of blocks, located one
after the other, of a kind described by the following struct type:

     type Block =
       struct
       {
          byte magic[2] : magic[0] == 'B' && magic[1] == 'K';
          ... other data ...
       };

   we can map the blocks using an unbounded array map:

     (poke) Block[] @ 0#B
     [ ... blocks ... ]

   If the blocks extend up to the end of the IO space, that many blocks
will be mapped.  If there is some other content in the file following
the blocks, the constraint in the 'magic' field will fail and will
delimit the map that way (provided the binary format is well designed.)


File: poke.info,  Node: Mapped bounds in bounded arrays,  Prev: Unbounded array maps,  Up: Mapping Arrays

20.15.5.4 Mapped bounds in bounded arrays
.........................................

When an array map is bounded, be it by number of elements or by size,
the bounding value can be mapped itself.  To illustrate how this works,
let's go back to our ELF file and the section containing relocations.
First, we map an 'Elf64_Shdr' to get the section header:

     (poke) var shdr = Elf64_Shdr @ OFFSET
     (poke) shdr.sh_offset
     120#B
     (poke) shdr.sh_size
     24#B

   Now we map an array with the relocations themselves, using a map
bounded by size, as we learned in the last section:

     (poke) var relocs = ELF64_Rela[shdr.sh_size] @ shdr.sh_offset
     (poke) relocs'length
     3

   Now, observe that 'shdr.sh_size' is mapped itself!  This means that,
should the section size be modified (to accommodate an extra relocation,
for example) the mapping of 'relocs' will reflect that automatically:

     (poke) shdr.sh_size = shdr.sh_size + 1#Elf64_Rela
     (poke) relocs'length
     4

   This is certainly an useful idiom, that is often used while poking
around.  However, sometimes this is _not_ what we want.  If we don't
want the mapping bounds of 'relocs' to be tied to 'shdr', we can just
use a temporary for the size:

     (poke) var s = shdr.sh_size
     (poke) var relocs = Elf64_Rela[s] @ shdr.sh_offset

   Since simple values (such as the size above) are not mapped, this
trick works as intended.


File: poke.info,  Node: Mapping Functions,  Next: Non-strict Mapping,  Prev: Mapping Arrays,  Up: Mapping

20.15.6 Mapping Functions
-------------------------

Struct fields can be of any type, and that includes function types or
closures.  This is especially useful to build interfaces.

   For orthogonality, it is possible to map function types.  The result
of the mapping is not very useful though: mapping a function type
results in a function with an empty body.  If the function returns a
value, a default value (zero for integral types, empty arrays for array
types, etc) is returned.

   Example:

     (poke) type Fun = (int) int
     (poke) Fun @ 0#B
     #<closure>
     (poke) (Fun @ 0#B) (10)
     0x0


File: poke.info,  Node: Non-strict Mapping,  Next: Auto-Remapping,  Prev: Mapping Functions,  Up: Mapping

20.15.7 Non-strict Mapping
--------------------------

The map operator '@' performs what we call a "strict mapping".  This
means that the data integrity of the mapped data is checked for.  Often
this is what we want.

   However, sometimes we have to work with incorrect or incomplete data.
In these cases, we want to inspect that data and complete it using poke.

   For this purpose poke provides an alternate map operator '@!' that
behaves exactly like the normal operator, but inhibits the control of
data integrity.

   The attribute ''strict' can be used to query whether a given value is
strict or non-strict.  Non-mapped values are strict by definition.


File: poke.info,  Node: Auto-Remapping,  Next: Unmapping,  Prev: Non-strict Mapping,  Up: Mapping

20.15.8 Auto-Remapping
----------------------

By default poke always tries to handle mapped values in a transparent
way, i.e.  in the same way than if the values weren't mapped.  To
guarantee that the contents of mapped values are always up to date, it
issues "remaps" every time the value gets referenced.

For example, consider the following Poke program:

     var arr = X86_Insn[1024];

There, an array of 1024 x86 instructions 'arr' is mapped.  Every time
the array value is referenced it is re-mapped from the corresponding IO
space.  For example:

     arr[2].opcode = 0x0b;

In the reference above, the whole array should be re-mapped from IO
space, because x86 instructions are variable-length, so it is necessary
to re-read all the previous values before accessing the element in
position 2.

   This re-mapping 100% guarantees that the mapped values are up to
date.  However, this can get very slow, depending on the data structures
we are poking at.

poke offers a way to turn this auto re-mapping off.  In Poke code:

     vm_set_autoremap (0)

Or using the poke application CLI:

     (poke) .set autoremap no

When auto-remap is switched off, mapped values are used as-is.  It is
then the responsibility of the user to explicitly re-map values using
the 'remap' operator.  Like:

     (poke) remap arr


File: poke.info,  Node: Unmapping,  Prev: Auto-Remapping,  Up: Mapping

20.15.9 Unmapping
-----------------

The unary 'unmap' operator has the form:

     unmap VALUE

   It gets any value and produces the same value, making it not mapped
in case it is a mapped value.

   This is useful when we want to read a data structure from the IO
space (say, an array of integers) and then use it for storage without
changing the underlying IO space.  We would do something like:

     (poke) var a = unmap (int[3] @ 10#B)
     (poke) a[2] = 100


File: poke.info,  Node: Exception Handling,  Next: Terminal,  Prev: Mapping,  Up: The Poke Language

20.16 Exception Handling
========================

Sometimes an error or some other unexpected situation arises.  Poke
provides an exceptions mechanism to deal with these situations.

* Menu:

* Exceptions::		List of supported exception types.
* try-catch::		Catching exceptions in programs.
* try-until::		Running code until some exception occurs.
* raise::		Raising exceptions in programs.
* exception-predicate:: Turning exceptions into booleans.
* assert::		Asserting conditions in programs.


File: poke.info,  Node: Exceptions,  Next: try-catch,  Up: Exception Handling

20.16.1 Exceptions
------------------

Exceptions in Poke are values of type 'Exception', which is a struct
defined like this:

     type Exception =
       struct
       {
         int<32> code;
         string msg;
       };

where 'code' identifies the type of the exception, and 'msg' is supposed
to be a textual description of the exceptional situation.

   You can use codes '255' and higher for your own exceptions.  For
example:

     raise Exception { code = 255; msg = "double upset event" };

   User-defined exceptions should be registered using 'exception_code'
function.  For example:

     var E_my_exception = Exception {
       code = exception_code,
       msg = "double upset event",
     };

where the 'E_my_exception.code' is a unique number greater than or equal
to '255'.

   Exception codes in the range '0..254' are reserved for poke.  These
are used in predefined exceptions which are standard, and have specific
meanings:

'E_generic'
     Generic error.
'E_out_of_bounds'
     Out of bounds exception.  This can be raised when accessing
     containers, like arrays and strings.
'E_eof'
     End of file exception.  This can be raised when mapping in the IO
     space.
'E_elem'
     Invalid element exception.  This is raised when attempting to
     access union fields that do not exist.
'E_constraint'
     Constraint violation exception.  This is raised when a constraint
     exception fails while mapping or constructing a struct.
'E_conv'
     Conversion exception.  This can be raised while casting values.
'E_map'
     No map exception.  This is raised when trying to map a not mapped
     value.
'E_div_by_zero'
     Division by zero exception.
'E_no_ios'
     No IOS exception.  This is raised when the IO space is accessed but
     there is no IO space.
'E_no_return'
     No return exception.  This is raised when the end of a non-void
     function is reached.
'E_io'
     Generic IO exception.
'E_io_flags'
     Invalid flags were tried while opening an IO device.
'E_assert'
     Assertion failure exception.  This is raised by 'assert' statement.
'E_overflow'
     This exception is raised when signed overflow is detected in an
     arithmetic operation.
'E_perm'
     This exception is raised when some operation can't be performed due
     to incorrect (lack of) permissions or capabilities.  An example is
     writing to a read-only IO space.

   The exception codes of the standard exceptions are available in the
form of 'EC_*' variables.  For example, this how you would raise an IO
error with a particular message:

     raise Exception { code = EC_io,
                        msg = "fluzo capacitator overheat impedes IO" }


File: poke.info,  Node: try-catch,  Next: try-until,  Prev: Exceptions,  Up: Exception Handling

20.16.2 'try-catch'
-------------------

The 'try-catch' statement provides a way to catch exceptions and handle
them.

   The simplest form of the statement is:

     try STMT catch COMPOUND_STMT

where STMT is any statement and COMPOUND_STMT is a compound statement.
First, STMT is executed.  If during its execution an exception is
raised, then COMPOUND_STMT is executed.

   The second form of the statement allows you to catch just one type of
exception:

     try STMT catch if EXP COMPOUND_STMT

where EXP is an expression that should evaluate to an 'Exception'.  The
handler COMPOUND_STMT will only be executed if that specific exception
is caught.  Any other exception will be re-raised.

   The third form of the statement is the most generic:

     try STMT catch (Exception FORMAL) COMPOUND_STMT

where FORMAL is a formal argument that contains the exception when
COMPOUND_STMT is executed.


File: poke.info,  Node: try-until,  Next: raise,  Prev: try-catch,  Up: Exception Handling

20.16.3 'try-until'
-------------------

The 'try-until' statement allows you to execute instructions until some
exception is caught.  The syntax is:

     try STMT until EXP

where STMT is the statement that will be executed repeatedly until some
exception is raised.  If the raised exception has type EXP then
execution continues normally.  EXP should be an expression that
evaluates to an 'Exception'.

   This statement is particularly useful for mapping IO spaces until an
'eof' condition occurs.  For example, this is how we would compute with
every integer in the current IO space:

     var o = 0#B;
     try
     {
       compute (int @ o);
       o = o + 1#B;
     } until E_eof;

   It is possible to leave the loop from within STMT using the 'break'
statement.


File: poke.info,  Node: raise,  Next: exception-predicate,  Prev: try-until,  Up: Exception Handling

20.16.4 'raise'
---------------

In previous sections we saw how exceptions are usually the side-product
of performing certain operations.  For example, a division by zero.

   However, it is also useful to explicitly raise exceptions.  The
'raise' statement can be used for that purpose.  Its syntax is:

     raise EXCEPTION;

where EXCEPTION is an integer.  This integer can be any number, but most
often is one of the 'E_*' codes defined in Poke.


File: poke.info,  Node: exception-predicate,  Next: assert,  Prev: raise,  Up: Exception Handling

20.16.5 exception-predicate
---------------------------

It is often needed to determine whether the execution of some given code
raised some particular exception.  A possibility is to use a 'try-catch'
statement like in the following example, a pretty-printer in an union
type:

     method _print = void:
     {
       try print "#<%u32d>", simple_value;
       catch if E_elem { print "%v\n", complex_value; }
     }

   This works as intended, but it is somewhat verbose and not that easy
to read for anyone not accustomed to the idiom.  It is better to use the
"exception predicate" operator, '?!', that has two forms:

     EXP ?! EXCEPTION
     { [STATEMENTS...] } ?! EXCEPTION

   In the first form, the expression EXP is executed.  If the execution
raises the exception EXCEPTION then the result of the predicate is '1'
(true), otherwise it is '0' (false).  The value of the expression is
discarded.

   In the second form, the compound statement passed as the first
operand is executed.  If the exception EXCEPTION is raised, then the
result of the predicate is '0' (false), otherwise it is '1' (true).

   Using exception predicates the pretty-printer above can be written in
a much more readable way:

     method _print = void:
     {
       if (simple_value ?! E_elem)
         print "%v\n", complex_value;
       else
         print "#<%u32d>", simple_value;
     }

Or, alternatively (and slightly more efficiently):

     method _print = void:
     {
       ({ print "<%u32d>", simple_value; } ?! E_elem)
         && print "%v\n", complex_value;
     }


File: poke.info,  Node: assert,  Prev: exception-predicate,  Up: Exception Handling

20.16.6 'assert'
----------------

The 'assert' statement allows you test if a condition is true, if not,
the program will raise an exception with code 'EC_assert'.

     assert (CONDITION)
     assert (CONDITION, MESSAGE)

   The optional MESSAGE will be part of the 'msg' field of raised
'Exception' to explain the situation.  If no MESSAGE is explicitly
specified, 'msg' is set to the source code of the expression evaluated
as the assert condition.

     assert (1 == 1);
     assert (0 == 0, ``Zero is equal to zero'');

   'assert' is useful for writing unit tests.


File: poke.info,  Node: Terminal,  Next: Printing,  Prev: Exception Handling,  Up: The Poke Language

20.17 Terminal
==============

Poke programs have access to a text-oriented terminal, that can be used
to communicate with the user.  The system provides several primitive
functions to manipulate the terminal, which are described in the
sections below.

* Menu:

* Terminal Colors::		Foreground and background colors.
* Terminal Styling::		Styling output with classes.
* Terminal Hyperlinks::         Click-able hyperlinks.


File: poke.info,  Node: Terminal Colors,  Next: Terminal Styling,  Up: Terminal

20.17.1 Terminal Colors
-----------------------

At every moment the text terminal is configured to use certain
foreground and background colors.  Initially, these are the "default
colors", which depend on the underlying terminal capabilities, and maybe
also on some system wide configuration setting.

   Terminal colors are encoded in triplets of integers signifying RGB
colors, i.e.  levels of beams for red, green and blue.  These triplets
are implemented as values of type 'int<32>[3]'.

   The special value '[-1, -1, -1]' means the default color, for both
foreground and background.  There are two predefined variables for this:

     var term_default_color = [-1,-1,-1];
     var term_default_bgcolor = [-1,-1,-1];

   Getting and setting the foreground and background colors is performed
using the 'term_get_color', 'term_set_color', 'term_get_fgcolor' and
'term_set_fgcolor' functions, with signatures:

     fun term_get_color = int<32>[3]
     fun term_set_color = (int<32>[3] color) void
     fun term_get_bgcolor = int<32>[3]
     fun term_set_bgcolor = (int<32>[3] color) void


File: poke.info,  Node: Terminal Styling,  Next: Terminal Hyperlinks,  Prev: Terminal Colors,  Up: Terminal

20.17.2 Terminal Styling
------------------------

Styling of the output sent to the terminal is supported in the form of
"styling classes".  Each class is characterized by a name, a string.

   A class is activated by using the function 'term_begin_class', and
deactivated by using the function 'term_end_class'.  Several classes can
be activated simultaneously, but they should be deactivated in reverse
order.  It is down to the implementation to decide how to honor some
given class, i.e.  to decide how to characterize it physically
(visually, or audibly, or using an electrical discharge on the keyboard,
or whatever) The class may very well be ignored all together.  Poke
programs should never rely on how a specific class is implemented.

   The 'term_begin_class' and 'term_end_class' functions have the
following signatures:

     fun term_begin_class = (string class) void
     fun term_end_class = (string class) void

Styling classes can overlap, but trying to deactivate them in the wrong
order will cause an error in the form of an 'E_inval' exception.


File: poke.info,  Node: Terminal Hyperlinks,  Prev: Terminal Styling,  Up: Terminal

20.17.3 Terminal Hyperlinks
---------------------------

The poke terminal supports terminal hyperlinks.  Each hyperlink is
characterized by an URL, and an ID. The 'term_begin_hyperlink' and
'term_end_hyperlink' functions have the following signatures:

     fun term_begin_hyperlink = (string url, string id) void
     fun term_end_hyperlink = void

Hyperlinks can overlap, but trying to end an hyperlink when there is no
t a currently open one will result in an 'E_generic' exception raised.


File: poke.info,  Node: Printing,  Next: Comments,  Prev: Terminal,  Up: The Poke Language

20.18 Printing
==============

Poke programs can print text to the standard output in two ways: simple
unformatted output, and formatted output.

* Menu:

* print::			simple output.
* printf::			formatted output.


File: poke.info,  Node: print,  Next: printf,  Up: Printing

20.18.1 'print'
---------------

The 'print' statement prints the given string to the standard output.
'print' outputs text strings verbatim.  It can be invoked using two
alternative syntaxes, which are equivalent:

     print (STR);
     print STR;

   'print' is simple, but fast.  It is good to use it in simple cases
where the information to print out doesn't require any kind of
formatting and styling.


File: poke.info,  Node: printf,  Prev: print,  Up: Printing

20.18.2 'printf'
----------------

The 'printf' statement gets a format string and, optionally, a list of
values to print.  It can be invoked using two alternative syntaxes,
which are equivalent:

     printf (FMT[, VALUE...])
     printf FMT[, VALUE...]

   The format string FMT is printed verbatim to the standard output, but
for "format tags" which start with '%'.  These format tags are
interpreted especially.  Most of the format tags "consume" one of the
specified values.  Every value in the list shall be described by a tag,
or the compiler will signal an error.  Likewise, values without a
corresponding describing tag is an error.  These tags are:

'%s'
     Print the argument as a string.
'%iBITS(d|x|o|b|c)'
     Print the argument as a signed integer of size BITS.  The last
     letter determines how the argument is printed.
     'd'
          Print the integer in decimal.
     'x'
          Print the integer in hexadecimal.
     'o'
          Print the integer in octal.
     'b'
          Print the integer in binary.
     'c'
          Print the integer as an ASCII character.  This only works with
          8 bit integers.
'%u'
     Same as '%i', but for unsigned integers.
'%c'
     A shorter way to write '%u8c'.
'%fBITS[.PRECISION]d'
'%eBITS[.PRECISION]d'
'%gBITS[.PRECISION]d'
     These tags accept integral values, that are cast to an integral
     value of width BITS and then interpreted as an IEEE 754
     floating-point number.  Currently, valid values for BITS are 32 and
     64.

     When using '%f' tag, the number will be printed in decimal notation
     in the style '[-]ddd.ddd', where the number of digits after the
     decimal-point character is equal to the PRECISION specification.
     The default PRECISION for '%f32' tag is 7 and for '%f64' is 15.

     The '%e' tag will print the number in the style '[-]d.ddde+-dd'
     where there is one digit (which is non-zero if the floating-point
     number is non-zero) before the decimal-point character and the
     number of digits after it is equal the PRECISION.  The exponent
     always contains at least two digits; if the value is zero, the
     exponent is 00.

     And '%g' tag will print the number in style '%f' or '%e'.  The
     PRECISION specifies the number of the significant digits.  Style
     '%e' is used if the exponent from its conversion is less than -4 or
     greater than or equal to the PRECISION.  Trailing zeros are removed
     from the fractional part of the result; a decimal point appears
     only if it is followed by at least one digit.

          (poke) printf ("%f64d\n", 0x40091eb851eb851fUL);
          3.140000000000000
          (poke) printf ("pi:%e32d\n", 0x4048f5c3U)
          pi:3.1400001e+00

'%v'
     Print the value printed representation of the argument, which can
     be of any type including complex types like arrays and structs.
     This is similar to the 'write' operation available in many Lisp
     systems.

     This tag supports an optional numerical argument (restricted to a
     single digit) that specifies the maximum depth level when printing
     structures.  Example:

          (poke) printf ("%1v\n", struct { s = struct { i = 10 },  l = 20L });
          struct {s=struct {...},l=0x14L}

     By default, the depth level is '0', which means no limit.

     This tag also support an optional flag that specifies how the value
     is printed.  The supported tags are 'F' (for "flat") and 'T' (for
     "tree").  The default is flat.  Example:

          (poke) printf ("%Tv\n", struct { s = struct { i = 10 },  l = 20L });
          struct {
            s=struct {
              i=0xa
            },
            l=0x14L
          }
          (poke) printf ("%Fv\n", struct { s = struct { i = 10 },  l = 20L });
          struct {s=struct {i=0xa},l=0x14L}

     This tag is mainly intended to be used in pretty-printers.

   The following format tags do not consume arguments.  They support
emitting styled text using the libtextstyle approach of having styling
classes that you can customize in a '.css' file.

'%<CLASSNAME:'
     Start the styling class with name CLASSNAME.  The class name cannot
     be empty.
'%>'
     End the last opened styling class.  All styling classes should be
     ended before finishing the format string.
'%%'
     Print '%' character.

   Note that styling classes can be nested, but all classes should be
ended before finishing the format string.

   If you use a NAME class, you can define how to style it in the '.css'
file (poke installs and uses poke-default.css but you can set the
'POKE_STYLE' environment variable to point to another css) like this:

     .NAME { text-decoration: blink; color : pink; }

   Examples:

     (poke) printf "This is a NAME: %<NAME:xxx%>"
     This is a NAME: xxx
     (poke) printf "Name: %<string:%s%> Age: %<integer:%i32d%>, "Jose", 39
     Name: Jose Age: 39


File: poke.info,  Node: Comments,  Next: Modules,  Prev: Printing,  Up: The Poke Language

20.19 Comments
==============

There are several ways to document your Poke programs: comments of
several types and support for separator characters.

* Menu:

* Multi-line comments::		C-like comments.
* Single line comments::	C++-like comments.
* Vertical separator::		Using form-feed characters.


File: poke.info,  Node: Multi-line comments,  Next: Single line comments,  Up: Comments

20.19.1 Multi-line comments
---------------------------

Poke supports C-like multi-line, comments, which is text enclosed
between '/*' and '*/' sequences.  These comments cannot be nested.


File: poke.info,  Node: Single line comments,  Next: Vertical separator,  Prev: Multi-line comments,  Up: Comments

20.19.2 Single line comments
----------------------------

C++-like single line comments are supported.  Everything after the '//'
sequence is interpreted as a comment, until the end of the line or the
end of the file, whatever comes first.


File: poke.info,  Node: Vertical separator,  Prev: Single line comments,  Up: Comments

20.19.3 Vertical separator
--------------------------

Poke ignores form feed characters (ASCII code 12, often visualized as
^L). In GNU software, this character is traditionally used to separate
conceptually different entities in source files.


File: poke.info,  Node: Modules,  Next: System,  Prev: Comments,  Up: The Poke Language

20.20 Modules
=============

It is common for pickles to depend on stuff defined in other pickles.
In such cases, the 'load' language construction can be used to load
pickles from your Poke program.  The syntax is:

     load MODULE;

where MODULE is the name of the pickle to load.

   For example, your Poke program may want to access some ELF data
structures.  In that case, we can just do:

     /* Pickle to poke the contents of some ELF section.  */

     load elf;

     /* ... code  ... */

   When asked to open a module, poke assumes it is implemented in a file
named 'MODULE.pk'.  In the example above, it will try to load 'elf.pk'.

   The pickles are searched first in the current working directory.  If
not found, then 'PREFIX/share/poke/MODULE.pk' is tried next.

   If the environment variable 'POKEDATADIR' is defined, it replaces
'PREFIX/share/poke'.  This is mainly intended to test a poke program
before it gets installed in its final location.

   Nothing prevents you to load the same pickle twice.  This will work
if the pickle doesn't include definitions, but just executes statements.
Otherwise, you will likely get an error due to trying to define stuff
twice.

   There is an alternate syntax of the 'load' construction that is
useful when the module is implemented in a file whose name doesn't
conform to a Poke identifier.  This happens, for example, when the file
name contains hyphens.  Example:

     load "my-pickle.pk";

   Note that if you use this variant of 'load', you must specify the
full file name, including whatever extension it uses (usually '.pk').


File: poke.info,  Node: System,  Next: VM,  Prev: Modules,  Up: The Poke Language

20.21 System
============

Poke provides several constructions to interact with the operating
system.  These are described in the subsections below.

* Menu:

* getenv::		Environment variables.
* rand::		Pseudo-random numbers.


File: poke.info,  Node: getenv,  Next: rand,  Up: System

20.21.1 getenv
--------------

The 'getenv' built-in function has the form:

     fun getenv (string name) string:

Given the name of an environment variable, it returns a string with its
value.  If the variable is not defined in the environment, then the
'E_inval' exception is raised.


File: poke.info,  Node: rand,  Prev: getenv,  Up: System

20.21.2 rand
------------

The 'rand' built-in function has the form:

     fun rand = (uint<32> seed = 0) int<32>:

It returns a pseudo-random number in the range of the unsigned 32-bit
integers.  If a SEED different to zero is provided, it is used to
initialize a new sequence of pseudo-random numbers (which includes the
one returned.)

   The 'gettime' builtin function can be used in order to seed the
pseudo-random number generator very easily:

     srand (gettime[1])


File: poke.info,  Node: VM,  Next: Debugging,  Prev: System,  Up: The Poke Language

20.22 VM
========

The Poke language provides a set of pre-defined functions which can be
used to access and modify properties of the underlying implementation
running the Poke programs.

* Menu:

* vm_obase::         Get the output base.
* vm_set_obase::     Set the output base.
* vm_opprint::       Get whether pretty-printers are used.
* vm_set_opprint::   Set whether pretty-printers are used.
* vm_oacutoff::      Get the cutoff limit for array printing.
* vm_set_oacutoff::  Set the cutoff limit for array printing.
* vm_odepth::        Get the maximum output depth level.
* vm_set_odepth::    Set the maximum output depth level.
* vm_oindent::       Get the output indentation step.
* vm_set_oindent::   Set the output indentation step.
* vm_omaps::         Get whether output maps get printed.
* vm_set_omaps::     Set whether output maps get printed.
* vm_omode::         Get the current output mode.
* vm_set_omode::     Set the current output mode.
* vm_autoremap::     Get whether re-mapping is on.
* vm_set_autoremap:: Set whether re-mapping is on.


File: poke.info,  Node: vm_obase,  Next: vm_set_obase,  Up: VM

20.22.1 'vm_obase'
------------------

The pre-defined function 'vm_obase' returns the current output base in
use in the underlying VM. It has the following prototype:

     fun vm_obase = int<32>:


File: poke.info,  Node: vm_set_obase,  Next: vm_opprint,  Prev: vm_obase,  Up: VM

20.22.2 'vm_set_obase'
----------------------

The pre-defined function 'vm_set_obase' sets the output base in the
underlying VM. It has the following prototype:

     fun vm_set_obase = (int<32> OBASE) void:

Where OBASE is the output base to set.  The base must be one of 2 (for
binary), 8 (for octal), 10 (for decimal) or 16 (for hexadecimal).  If
the provided base is not contained in that set, 'vm_set_obase' raises
'E_inval'.


File: poke.info,  Node: vm_opprint,  Next: vm_set_opprint,  Prev: vm_set_obase,  Up: VM

20.22.3 'vm_opprint'
--------------------

The pre-defined function 'vm_opprint' returns a boolean indicating
whether pretty-printers are used when printing struct values, or not.
It has the following prototype:

     fun vm_opprint = int<32>:


File: poke.info,  Node: vm_set_opprint,  Next: vm_oacutoff,  Prev: vm_opprint,  Up: VM

20.22.4 'vm_set_opprint'
------------------------

The pre-defined function 'vm_set_opprint' sets a flag in the underlying
VM, indicating whether pretty-printers are used when printing struct
values.  It has the following prototype:

     fun vm_set_opprint = (int<32> PRETTY_PRINT_P) void:


File: poke.info,  Node: vm_oacutoff,  Next: vm_set_oacutoff,  Prev: vm_set_opprint,  Up: VM

20.22.5 'vm_oacutoff'
---------------------

The pre-defined function 'vm_oacutoff' returns an integer indicating the
current cutoff limit used when printing array values.  It has the
following prototype:

     fun vm_oacutoff = int<32>:


File: poke.info,  Node: vm_set_oacutoff,  Next: vm_odepth,  Prev: vm_oacutoff,  Up: VM

20.22.6 'vm_set_oacutoff'
-------------------------

The pre-defined function 'vm_set_oacutoff' sets the current cutoff limit
used when printing array values.  It has the following prototype:

     fun vm_set_oacutoff = (int<32> CUTOFF) void:

where CUTOFF is an integer specifying the maximum number of array
elements that get printed.


File: poke.info,  Node: vm_odepth,  Next: vm_set_odepth,  Prev: vm_set_oacutoff,  Up: VM

20.22.7 'vm_odepth'
-------------------

The pre-defined function 'vm_odepth' returns an integer indicating the
maximum depth level used when printing nested structures.  It has the
following prototype:

     fun vm_odepth = int<32>:


File: poke.info,  Node: vm_set_odepth,  Next: vm_oindent,  Prev: vm_odepth,  Up: VM

20.22.8 'vm_set_odepth'
-----------------------

The pre-defined function 'vm_set_odepth' sets the maximum depth level to
be used when printing nested structures.  It has the following
prototype:

     fun vm_set_odepth = (int<32> DEPTH_LEVEL) void:

where DEPTH_LEVEL specifies the number of depth levels in nested structs
to consider when printing nested structures.


File: poke.info,  Node: vm_oindent,  Next: vm_set_oindent,  Prev: vm_set_odepth,  Up: VM

20.22.9 'vm_oindent'
--------------------

The pre-defined function 'vm_oindent' returns an integer indicating the
indentation step.  It has the following prototype:

     fun vm_oindent = int<32>:


File: poke.info,  Node: vm_set_oindent,  Next: vm_omaps,  Prev: vm_oindent,  Up: VM

20.22.10 'vm_set_oindent'
-------------------------

The pre-defined function 'vm_set_oindent' sets the indentation level
used when printing nested structures.  It has the following prototype:

     fun vm_set_oindent = (int<32> STEP) void:

where STEP specifies how much to indent when printing nested structures.
This value typically translates into the number of white spaces (or
tabs) used in terminals, but this must not be relied on since other
printing media may interpret it differently.


File: poke.info,  Node: vm_omaps,  Next: vm_set_omaps,  Prev: vm_set_oindent,  Up: VM

20.22.11 'vm_omaps'
-------------------

The pre-defined function 'vm_omaps' returns a boolean indicating whether
offset information is included when printing out values.  It has the
following prototype:

     fun vm_omaps = int<32>:


File: poke.info,  Node: vm_set_omaps,  Next: vm_omode,  Prev: vm_omaps,  Up: VM

20.22.12 'vm_set_omaps'
-----------------------

The pre-defined function 'vm_set_omaps' sets whether offset information
is included when printing out values.  It has the following prototype:

     fun vm_set_omaps = (int<32> OMAPS_P) void:


File: poke.info,  Node: vm_omode,  Next: vm_set_omode,  Prev: vm_set_omaps,  Up: VM

20.22.13 'vm_omode'
-------------------

The pre-defined function 'vm_omode' returns an integer indicating the
currently enabled output mode.  It has the following prototype:

     fun vm_omode = int<32>:

There are currently two supported output modes:

     var VM_OMODE_PLAIN = 0;
     var VM_OMODE_TREE = 1;


File: poke.info,  Node: vm_set_omode,  Next: vm_autoremap,  Prev: vm_omode,  Up: VM

20.22.14 'vm_set_omode'
-----------------------

The pre-defined function 'vm_set_omode' sets the output mode to use by
default when printing values.  It has the following prototype:

     fun vm_set_omode = (int<32> OMODE) void:

Where OMODE is one of the 'VM_OMODE_*' values documented above.


File: poke.info,  Node: vm_autoremap,  Next: vm_set_autoremap,  Prev: vm_set_omode,  Up: VM

20.22.15 'vm_autoremap'
-----------------------

The pre-defined function 'vm_autoremap' returns a boolean indicating
whether auto-remapping of mapped values is switched on.  It has the
following prototype:

     fun vm_autoremap = int<32>:


File: poke.info,  Node: vm_set_autoremap,  Prev: vm_autoremap,  Up: VM

20.22.16 'vm_set_autoremap'
---------------------------

The pre-defined function 'vm_set_autoremap' sets whether auto-remapping
of mapped values is switched on.  It has the following protoype:

     fun vm_set_autoremap = (int<32)void:


File: poke.info,  Node: Debugging,  Prev: VM,  Up: The Poke Language

20.23 Debugging
===============

* Menu:

* __LINE__ and __FILE__::	Error locations in traces.
* strace::                      Printing out PVM stack traces


File: poke.info,  Node: __LINE__ and __FILE__,  Next: strace,  Up: Debugging

20.23.1 '__LINE__' and '__FILE__'
---------------------------------

When printing traces it is often useful to include a description of the
location of the trace.  The poke compiler provides two builtins for this
purpose.

'__LINE__'
     Expands to an unsigned 64-bit integer containing the current line
     of the program being compiled.
'__FILE__'
     Expands to a string with the name of the file currently being
     compiled.  If the program is read from the standard input (like in
     the REPL) then this is '"<stdin>"'.


File: poke.info,  Node: strace,  Prev: __LINE__ and __FILE__,  Up: Debugging

20.23.2 strace
--------------

The 'strace' built-in function has the prototype:

     fun strace = void:

It prints out the current contents of the PVM stack.  This is especially
useful to debug the code generated by the compiler.


File: poke.info,  Node: The Standard Library,  Next: The Poke Virtual Machine,  Prev: The Poke Language,  Up: Top

21 The Standard Library
***********************

GNU poke ships with a standard library for Poke programs that is
available to Poke programs.  The following sections detail the
facilities provided by the library.

* Menu:

* Standard Integral Types::	int, long and the like.
* Standard Offset Types::	off64 and the like.
* Standard Units::		b, B, Kb and the like.
* Conversion Functions::	catos, atoi, etc.
* Array Functions::             Functions which deal with arrays.
* String Functions::		Functions which deal with strings.
* Character Functions::         Functions which deal with characters.
* Values Functions::            Functions which deal with values in general.
* IO Space Functions::          Functions that operate on IO spaces.
* Sorting Functions::		qsort.
* CRC Functions::               Cyclic Redundancy Checksums.
* Dates and Times::             Processing and displaying dates and times.
* Offset Functions::            Useful functions that operate on offsets.
* Other Functions::             Miscellany.


File: poke.info,  Node: Standard Integral Types,  Next: Standard Offset Types,  Up: The Standard Library

21.1 Standard Integral Types
============================

The Poke standard library provides the following standard integral
types.

'bit'
     1-bit unsigned integer.
'nibble'
     4-bit unsigned integer.
'uint8'
'byte'
'char'
     8-bit unsigned integer.
'uint16'
'ushort'
     16-bit unsigned integer.
'uint32'
'uint'
     32-bit unsigned integer.
'uint64'
'ulong'
     64-bit unsigned integer.
'int8'
     8-bit signed integer.
'int16'
'short'
     16-bit signed integer.
'int32'
'int'
     32-bit signed integer.
'int64'
'long'
     64-bit signed integer.


File: poke.info,  Node: Standard Offset Types,  Next: Standard Units,  Prev: Standard Integral Types,  Up: The Standard Library

21.2 Standard Offset Types
==========================

The Poke standard library provides the following standard offset types.

'off64'
     64-bit signed offset in bits.
'uoff64'
     64-bit unsigned offset in bits.


File: poke.info,  Node: Standard Units,  Next: Conversion Functions,  Prev: Standard Offset Types,  Up: The Standard Library

21.3 Standard Units
===================

The following list of units are defined in the standard library.

Base units:

'b'
     bits.
'N'
     nibbles.
'B'
     bytes.

Base 10 units:

'Kb'
     kilo bits (1000 bits.)
'KB'
     Kilo bytes (1000 bytes.)
'Mb'
     Mega bits.
'MB'
     Mega bytes.
'Gb'
     Giga bits.
'GB'
     Giga bytes.

Base 2 units:

'Kib'
     kilo bits (1000 bits.)
'KiB'
     Kilo bytes (1000 bytes.)
'Mib'
     Mega bits.
'MiB'
     Mega bytes.
'Gib'
     Giga bits.
'GiB'
     Giga bytes.


File: poke.info,  Node: Conversion Functions,  Next: Array Functions,  Prev: Standard Units,  Up: The Standard Library

21.4 Conversion Functions
=========================

The Poke standard library provides the following functions to do useful
conversions.

* Menu:

* catos::		converting characters arrays into string.
* stoca::		filling character arrays from strings.
* strtoi::		convert numeric prefix to integer.
* atoi::		converting strings to integers.
* ltos::		converting integers to strings.


File: poke.info,  Node: catos,  Next: stoca,  Up: Conversion Functions

21.4.1 'catos'
--------------

It is often useful to convert arrays of characters into strings.  The
standard function 'catos' provides the following interface:

     fun catos = (char[] CHARS) string: { ... }

   It builds a string containing the characters in CHARS, and returns
it.  Examples:

     (poke) catos (['a','b','c'])
     "abc"
     (poke) catos (['\0'])
     ""

   Note that if the passed array contains a 'NULL' character ''\0'' then
no further characters are processed.  For example:

     (poke) catos (['f','o','o','\0','b','a','r'])
     "foo"


File: poke.info,  Node: stoca,  Next: strtoi,  Prev: catos,  Up: Conversion Functions

21.4.2 'stoca'
--------------

Sometimes we want to store strings in character arrays.  The standard
function 'stoca' provides the following interface:

     fun stoca = (string s, char[] ca, char fill = 0) void: { ... }

   It fills the given array CA with the contents of the string S.  If
the string doesn't fit in the array, then 'E_out_of_bounds' is raised.
If the length of the string is less than the length of the array, the
extra characters are set to the FILL character, which defaults to '\0'.


File: poke.info,  Node: strtoi,  Next: atoi,  Prev: stoca,  Up: Conversion Functions

21.4.3 'strtoi'
---------------

The standard function 'strtoi' provides the following interface:

     type Strtoi_Result =
       struct
       {
         uint<64> OFF;
         int<64> VAL;
       };

     fun strtoi = (string STR, int BASE = 10, ulong START = 0) Stroi_Result: { ... }

   It parses a signed integral number in the given BASE in the string
STR at position START and returns its value and its length in the VAL
and OFF fields of a new 'Strtoi_Result' instance.

   Specifying a START that is greater than or equal to the length of the
string causes a 'E_out_of_bound' exception to be raised.

   The accepted values for BASE are '2', '8', '10' (the default) and
'16'.  If any other base is requested an 'E_inval' exception is raised.

   Note that this function parses an integer but permits more characters
to follow the given integer.  As an example, take a look at parsing
"12foo" in base 16:

     #!!# strtoi ("12foo", 16)
     Strtoi_Result {
       off=3UL,
       val=303L
     }
     #!!# strtoi ("12foo", 16, 1)
     Strtoi_Result {
       off=3UL,
       val=47L
     }


File: poke.info,  Node: atoi,  Next: ltos,  Prev: strtoi,  Up: Conversion Functions

21.4.4 'atoi'
-------------

The standard function 'atoi' provides the following interface:

     fun atoi = (string STR, int BASE = 10) long: { ... }

   It parses a signed integral number in the given BASE in the string
STR and returns it as a signed 64-bit integer.

   The accepted values for BASE are the same as for 'strtoi'.  *Note
strtoi:: for a list of supported bases.

   Note that atoi allows for extra information to be stored in STR after
the parsed integer.  Thus, this works:

     (poke) atoi ("10foo")
     10L


File: poke.info,  Node: ltos,  Prev: atoi,  Up: Conversion Functions

21.4.5 'ltos'
-------------

The 'ltos' standard function converts a given long integer into its
printed representation in some given base.  It has the following
prototype:

     fun ltos = (long I, uint BASE = 10) string:

where I is the number for which to calculate the printed representation,
and BASE is a number between 0 and 16.


File: poke.info,  Node: Array Functions,  Next: String Functions,  Prev: Conversion Functions,  Up: The Standard Library

21.5 Array Functions
====================

The Poke standard library provides the following functions to do work on
arrays:

* Menu:

* reverse::		Reverse the elements of a given array.


File: poke.info,  Node: reverse,  Up: Array Functions

21.5.1 'reverse'
----------------

The standard function 'reverse' provides the following interface:

     fun reverse = (any[] a) void:

It reverses the elements of the given array.


File: poke.info,  Node: String Functions,  Next: Character Functions,  Prev: Array Functions,  Up: The Standard Library

21.6 String Functions
=====================

The Poke standard library provides the following functions to do work on
strings:

* Menu:

* ltrim::		Remove leading characters.
* rtrim::		Remove trailing characters.
* strchr::		Locate a character in a string, from the beginning.
* strrchr::		Locate a character in a string, from the end.
* strtok::		String tokenization.


File: poke.info,  Node: ltrim,  Next: rtrim,  Up: String Functions

21.6.1 'ltrim'
--------------

The standard function 'ltrim' provides the following interface:

     fun ltrim = (string s, string cs = " \t") string: { ... }

   It returns a copy of the input string 's' with any leading character
that also appears in CS removed.


File: poke.info,  Node: rtrim,  Next: strchr,  Prev: ltrim,  Up: String Functions

21.6.2 'rtrim'
--------------

The standard function 'rtrim' provides the following interface:

     fun rtrim = (string s, string cs = " \t") string: { ... }

   It returns a copy of the input string 's' with any trailing character
that also appears in CS removed.


File: poke.info,  Node: strchr,  Next: strrchr,  Prev: rtrim,  Up: String Functions

21.6.3 'strchr'
---------------

The standard function 'strchr' provides the following interface:

     fun strchr = (string s, uint<8> c) int<32>: { ... }

   It returns the index of the first occurrence of the character C in
the string S.  If the character is not found in the string, this
function returns the length of the string.


File: poke.info,  Node: strrchr,  Next: strtok,  Prev: strchr,  Up: String Functions

21.6.4 'strrchr'
----------------

The standard function 'strrchr' provides the following interface:

     fun strrchr = (string s, uint<8> c) int<32>: { ... }

   It returns the index of the last occurrence of the character C in the
string S.  If the character is not found in the string, this function
returns -1.


File: poke.info,  Node: strtok,  Prev: strrchr,  Up: String Functions

21.6.5 'strtok'
---------------

'strtok' is a helper for tokenizing strings.  The synopsis of this API
are:

     type String_Tokenizer =
       struct
       {
         uint<64> i;
         string str;
         computed uint<32> more;

         method get_more = uint<32>: { ... }

         method peek = char: { ... }
         method pop = char: { ... }

         method pop_number = (int<32> BASE = 10) int<64>: { ... }

         method popdelim = (string DELIMITERS) string: { ... }
         method poprdelim = (string DELIMITERS) string: { ... }
       }

     fun strtok = (string A) String_Tokenizer: { ... }

 -- Function: String_Tokenizer strtok (string A)
     Creates a new tokenizer for the string A, initially on the zero
     position.

   The members of the 'String_Tokenizer' class are:

 -- Instance Variable of String_Tokenizer: uint<64> i
     Offset to the next character to be tokenized, i.e.  to the first
     character that has not already been consumed.

 -- Instance Variable of String_Tokenizer: string str
     The string being tokenized.  This string is never tokenized.

 -- Instance Variable of String_Tokenizer: uint<32> more
     A read-only computed property whose value is truthy if there's more
     characters and falsey otherwise.

 -- Method on String_Tokenizer: char poke ()
     Returns the first unread character of the string, but does not
     advance the I offset.

     Raises 'E_out_of_bounds' if at the end of the string.

 -- Method on String_Tokenizer: char peek ()
     Returns the first unread character of the string, and advances the
     tokenizer.

     Raises 'E_out_of_bounds' if at the end of the string.

 -- Method on String_Tokenizer: int<64> pop_number (int<32> BASE = 10)
     Returns the number at the start of the string and advances the
     tokenizer in the given BASE.  The bases that are supported are the
     same as for 'strtoi'.  *Note strtoi:: for a list of supported
     bases.

     Raises 'E_out_of_bounds' if at the end of the string.

 -- Method on String_Tokenizer: string popdelim (string DELIM)
     Returns the substring up to the first character also present in the
     string DELIM.  Advances the tokenizer to after the delimiter
     character (i.e.  it consumes the delimiter character).

     Raises 'E_out_of_bounds' if at the end of the string.

 -- Method on String_Tokenizer: string poprdelim (string DELIM)
     Returns the substring up to the last character also present in the
     string DELIM.  Advances the tokenizer to after the delimiter
     character (i.e.  it consumes the delimiter character).

     Raises 'E_out_of_bounds' if at the end of the string.


File: poke.info,  Node: Character Functions,  Next: Values Functions,  Prev: String Functions,  Up: The Standard Library

21.7 Character Functions
========================

The Poke standard library provides the following functions to deal with
characters:

* Menu:

* isdigit::             Is given character a decimal digit?
* isxdigit::            Is given character a hexadecimal digit?


File: poke.info,  Node: isdigit,  Next: isxdigit,  Up: Character Functions

The standard function 'isdigit' provides the following interface:

     fun isdigit = (uint<8> C) int<32>

it returns 0 when the given ASCII character C is not a decimal digit,
otherwise it returns a non-zero value.


File: poke.info,  Node: isxdigit,  Prev: isdigit,  Up: Character Functions

The standard function 'isxdigit' provides the following interface:

     fun isxdigit = (uint<8> C) int<32>

it returns 0 when the given ASCII character C is not a hexadecimal
digit, otherwise it returns a non-zero value.


File: poke.info,  Node: Values Functions,  Next: IO Space Functions,  Prev: Character Functions,  Up: The Standard Library

21.8 Values Functions
=====================

The Poke standard library provides the following functions to handle
values in general:

* Menu:

* eoffset::		Offset of a value's element by name.


File: poke.info,  Node: eoffset,  Up: Values Functions

21.8.1 'eoffset'
----------------

The standard function 'eoffset' provides the following interface:

     fun eoffset = (any val, string name) offset<uint<64>,b>

It returns the offset of the element having the given name in the given
composite value.  If the value doesn't contain an element with the given
name then the exception 'E_inval' is raised.


File: poke.info,  Node: IO Space Functions,  Next: Sorting Functions,  Prev: Values Functions,  Up: The Standard Library

21.9 IO Space Functions
=======================

* Menu:

* with_cur_ios::        Executing code on a given IO space.
* with_temp_ios::       Executing code on a temporary IO space.


File: poke.info,  Node: with_cur_ios,  Next: with_temp_ios,  Up: IO Space Functions

21.9.1 'with_cur_ios'
---------------------

The standard function 'with_cur_ios' provides the following interface:

     fun with_cur_ios = (int<32> IOS,
                         Pk_With_Ios_Fn DO = lambda void:{},
                         int<32> ENDIAN = get_endian) void:

   Where IOS is an IO space identifier, DO is a function of type
'()void' that defaults to a function that does nothing, and ENDIAN is
the endianness to use by default when accessing IOS.

   When invoked it switches to the given IO space and executes the given
function.  Once the function finishes executing, either by returning or
by the raise of an exception, the current IO space and endianness are
restored to their previous values.


File: poke.info,  Node: with_temp_ios,  Prev: with_cur_ios,  Up: IO Space Functions

21.9.2 'with_temp_ios'
----------------------

The standard function 'with_temp_ios' provides the following interface:

     fun with_temp_ios = (string HANDLER = pk_get_unique_mem_ios_handler,
                          uint<32> FLAGS = 0,
                          Pk_With_Ios_Fn DO = lambda void:{},
                          int<32> ENDIAN = get_endian) void:

   Where HANDLER is the handler to use for the IO space.

   FLAGS are the flags passed to 'open' when opening the temporary IO
space.  Defaults to 0, which means to use whatever opening mode makes
more sense depending on the kind of the IO space and it's permissions.

   DO is a function of type '()void'.  Defaults to a function that does
nothing.

   ENDIAN is the endianness to use by default when accessing the
temporary IO space.  Defaults to the current endianness.

   When invoked it opens a IO space, like 'openset', but takes care of
calling 'close' and restoring the original current IO space and
endianness after the lambda returns or raises an exception.

   It can be used to deal with files without risk of leaking file
descriptors.

     with_cur_ios
       :handler "*buf*"
       :do lambda void:
       {
         var arr = uint<32>[1]  0#B;
         arr[0] = 0x1234;
         printf("%v", byte[4]  0#b);
       }


File: poke.info,  Node: Sorting Functions,  Next: CRC Functions,  Prev: IO Space Functions,  Up: The Standard Library

21.10 Sorting Functions
=======================

* Menu:

* qsort::		Sorting arrays with quicksort.


File: poke.info,  Node: qsort,  Up: Sorting Functions

21.10.1 'qsort'
---------------

The standard function 'qsort' has the following prototype:

     fun qsort = (any[] ARRAY, Comparator CMP_F,
                    long LEFT = 0,
                    long RIGHT = array'length - 1) void

where ARRAY is the array to sort, CMP_F is a comparator function, LEFT
is the index of the first array element to include in the sorting, and
RIGHT is the index of the last array element to include in the sorting.
Both LEFT and RIGHT are optional, and the default is to cover the whole
array.

   The comparator function CMP_F should have the following prototype:

     type Comparator = (any,any)int<32>;

for example:

     fun CompareInts = (any a, any b) int<32>:
     {
       var ai = a as int<32>;
       var bi = b as int<32>;

       if (ai == bi)
         return 0;
       else if (ai > bi)
         return 1;
       else
         return -1;
     }


File: poke.info,  Node: CRC Functions,  Next: Dates and Times,  Prev: Sorting Functions,  Up: The Standard Library

21.11 CRC Functions
===================

Many file formats use checksums of one sort or another.  Therefore you
may want to write such a checksum or verify a checksum in a constrained
field.  *Note Field Constraints::.

   Some formats use simple additive checksums.  Another common checksum
is the Cyclic Redundancy Checksum (CRC). The standard function 'crc32'
calculates the 32 bit CRC defined by ISO-3309.

     fun crc32 = (byte[] BUF) uint<32>: { ... }

This function returns the 32 bit CRC for the data contained in the array
BUF.


File: poke.info,  Node: Dates and Times,  Next: Offset Functions,  Prev: CRC Functions,  Up: The Standard Library

21.12 Dates and Times
=====================

Often a format encodes a date and time expressed as the number of
seconds since midnight, January 1st 1970.  You could map these simply as
integers.  However, the standard library provides two types
'POSIX_Time32' and 'POSIX_Time64' which include pretty-printers to
display the date in a human readable format.  The definition is:

     type POSIX_TimeSIZE = struct
     {
       uint<SIZE>  seconds;

       method _print = void:
       { ... }
     }

where SIZE is either 32 or 64.  When pretty printing is enabled, a
mapped value of these types will display similar to

     #<2019-Dec-12 8:54:56>

whereas when pretty printing is not enabled, this example would be
displayed as:

     POSIX_Time32 {seconds=1576140896U}

Note that timestamps of this type do not account for leap seconds and
are agnostic towards timezone.

   Occasionally you might wish to print an unmapped timestamp value in a
human readable format.  To do this, you can use the 'ptime' function,
which is defined as follows:

     fun ptime = (uint<64> seconds) void:
     { ... }

   This pickle also provides a type 'Timespec' that can store Unix times
to nanosecond precision, and has the form:

     type Timespec = struct
     {
       int<64> sec;
       int<64> nsec;
     };

   The function 'gettimeofday' uses the 'gettime' builtin in order to
construct an instance of 'Timespec'.  For example:

     (poke) gettimeofday
     Timespec {
       sec=1604918423L,
       nsec=753492546L
     }
     (poke) ptime (gettimeofday.sec)
     2020-Nov-9 10:40:36


File: poke.info,  Node: Offset Functions,  Next: Other Functions,  Prev: Dates and Times,  Up: The Standard Library

21.13 Offset Functions
======================

* Menu:

* alignto::             Align an offset to a given alignment.


File: poke.info,  Node: alignto,  Up: Offset Functions

21.13.1 alignto
---------------

The 'alignto' function has the prototype:

     fun alignto = (uoff64 offset, uoff64 to) uoff64:
     { ... }

It returns an offset that is the result of aligning the given OFFSET to
the given alignment TO.


File: poke.info,  Node: Other Functions,  Prev: Offset Functions,  Up: The Standard Library

21.14 Other Standard Library Functions
======================================

The Poke standard library also provides the following functions that do
not fit into the previous few categories:

* Menu:

* Version Tools::		GNU poke version string utilities.


File: poke.info,  Node: Version Tools,  Up: Other Functions

21.14.1 GNU poke Version String Parsing Utilities
-------------------------------------------------

The Poke standard library provides utilities for parsing and comparing
GNU poke versions, to allow you to implement conditional code paths or
to check prerequisites.

 -- Variable: string pk_version
     Version string of the current instance of GNU poke.

   Note that these functions are _not_ generic to any version string, as
they assume and verify the version strings generated by the GNU poke
build system.

   The GNU poke version string that this family of functions accepts fit
the following template: 'X.Y[.Z][-BRANCH-NN][-gXDIGITS][-dirty]'.
Individually, these components are:

'X'
     The major component of this GNU poke version.  Mandatory.

'Y'
     The minor component of this GNU poke version.  Mandatory.

'Z'
     The subminor component of this GNU poke version.  Optional.

'BRANCH'
     A free-form string signifying the current branch a given GNU poke
     build comes from.  Optional.  It has two special values:

     'maint'
          For maintenance branches.
     'dev'
          For the 'master' development branch.

     All values other than 'dev' are considered equal and lower than
     'dev' by the comparison helper described below..

'NN'
     The number commits on 'BRANCH' since the 'X.Y[.Z]' tag.  Present if
     and only if 'BRANCH' is present.  This component is also called the
     offset.

'XDIGITS'
     The abbreviated commit hash this build was generated on.  For the
     purposes of these functions, it is optional, however, in practice,
     it can only appear when 'BRANCH' is also present.  Due to the '-g'
     prefix, this component also makes a poke version string appropriate
     for Git operations, for example: 'git show 3.0-dev-22-g2e092'.

'-dirty'
     This suffix is added if the Git tree this GNU poke version was
     built from is dirty.

   The standard library provides the following structured representation
of GNU poke versions:

     type Pk_Version =
       struct
       {
         uint<8> major;
         uint<8> minor;
         uint<8> subminor;
         string branch;
         uint<32> offset;
         string commit;

         uint<8> has_branch_p;
         uint<8> has_subminor_p;
         uint<8> has_commit_p;
         uint<8> dirty_p;
       };

 -- Function: string Pk_Version.to_string ()
     Method that returns the printed representation of a version.

 -- Function: Pk_Version pk_version_parse (string VERSION)
     Parses the string VERSION into a new instance of 'Pk_Version', or
     raises 'E_inval' if the string is invalid.

   The standard library also provides the following helper function:

 -- Function: int<32> pk_vercmp (any A, any B)
     Returns a number greater than, equal to, or lower than zero if A
     compares greater than, equal to or lower than B, respectively, as a
     GNU poke version.

     The type of A and B must be either 'string' or 'Pk_Version',
     otherwise, this function raises an 'E_conv'.

     This function implements partial ordering, as it's not possible to
     distinguish some version numbers as greater or lower than each
     other, as some could be seen as "lateral" to eachother.  For
     instance, consider the strings '3.0-a-11-gabcdef' and
     '3.0-b-11-gabcdef'.  They are both 11 commits ahead of the 3.0
     release, but they aren't on the same lineage, and so, they can't be
     considered as greater or lower than eachother.  In cases like
     these, 'pk_vercmp' will attempt to compare commit numbers as a
     crude measure.


File: poke.info,  Node: The Poke Virtual Machine,  Next: Table of ASCII Codes,  Prev: The Standard Library,  Up: Top

22 The Poke Virtual Machine
***************************

* Menu:

* PVM Instructions::		Virtual Machine instructions.


File: poke.info,  Node: PVM Instructions,  Up: The Poke Virtual Machine

22.1 PVM Instructions
=====================

* Menu:

* VM instructions::
* IOS related instructions::
* Function management instructions::
* Environment instructions::
* Printing Instructions::
* Format Instructions::
* Main stack manipulation instructions::
* Registers manipulation instructions::
* Return stack manipulation instructions::
* Arithmetic instructions::
* Relational instructions::
* Concatenation instructions::
* Logical instructions::
* Bitwise instructions::
* Shift instructions::
* Compare-and-swap instructions::
* Branch instructions::
* Conversion instructions::
* String instructions::
* Array instructions::
* Struct instructions::
* Offset Instructions::
* Instructions to handle mapped values::
* Type related instructions::
* IO instructions::
* Exceptions handling instructions::
* Debugging Instructions::
* System Interaction Instructions::
* Miscellaneous Instructions::


File: poke.info,  Node: VM instructions,  Next: IOS related instructions,  Up: PVM Instructions

22.1.1 VM instructions
----------------------

* Menu:

* Instruction canary::
* Instruction exit::
* Instruction pushend::
* Instruction popend::
* Instruction pushob::
* Instruction popob::
* Instruction pushom::
* Instruction popom::
* Instruction pushoo::
* Instruction popoo::
* Instruction pushoi::
* Instruction popoi::
* Instruction pushod::
* Instruction popod::
* Instruction pushoac::
* Instruction popoac::
* Instruction pushopp::
* Instruction popopp::
* Instruction pushoc::
* Instruction popoc::
* Instruction pushobc::
* Instruction popobc::
* Instruction sync::
* Instruction pusharem::
* Instruction poparem::


File: poke.info,  Node: Instruction canary,  Next: Instruction exit,  Up: VM instructions

22.1.1.1 Instruction canary
...........................

Synopsys:

     canary

   This instruction installs a canary to mark the bottom of the stack,
which is checked by the 'exit' instruction.  To be most effective this
should be executed before the stack is used for the first time.

   Stack: '( -- )'


File: poke.info,  Node: Instruction exit,  Next: Instruction pushend,  Prev: Instruction canary,  Up: VM instructions

22.1.1.2 Instruction exit
.........................

Synopsys:

     exit

   Do some cleanup and finish execution of a PVM program.  This checks
the stack sentinel installed by the 'canary' instruction.

   Stack: '( -- )'


File: poke.info,  Node: Instruction pushend,  Next: Instruction popend,  Prev: Instruction exit,  Up: VM instructions

22.1.1.3 Instruction pushend
............................

Synopsys:

     pushend

   Push the current endianness on the stack.  This endianness is part of
the global state of the PVM.

   Stack: '( -- INT )'


File: poke.info,  Node: Instruction popend,  Next: Instruction pushob,  Prev: Instruction pushend,  Up: VM instructions

22.1.1.4 Instruction popend
...........................

Synopsys:

     popend

   Pop a signed integer from the stack and make it the current
endianness in the PVM. The possible values for endianness are
IOS_ENDIAN_LSB and IOS_ENDIAN_MSB.

   Stack: '( INT -- )'


File: poke.info,  Node: Instruction pushob,  Next: Instruction popob,  Prev: Instruction popend,  Up: VM instructions

22.1.1.5 Instruction pushob
...........................

Synopsys:

     pushob

   Push output base.

   This instruction pushes a signed integer value with the output base
that is used when printing PVM values.  Valid values are 2, 8, 10 and
16.

   Stack: '( -- INT )'


File: poke.info,  Node: Instruction popob,  Next: Instruction pushom,  Prev: Instruction pushob,  Up: VM instructions

22.1.1.6 Instruction popob
..........................

Synopsys:

     popob

   Pop and set output base.

   This instructions pops a signed integer from the stack and uses it to
set the new output base to be used when printing PVM values.  Valid
values are 2, 8, 10 and 16.

   If an invalid obase is specified then this instruction raises
PVM_E_INVAL.

   Stack: '( INT -- )'

   Exceptions: 'PVM_E_INVAL'


File: poke.info,  Node: Instruction pushom,  Next: Instruction popom,  Prev: Instruction popob,  Up: VM instructions

22.1.1.7 Instruction pushom
...........................

Synopsys:

     pushom

   Push output mode.

   This instruction pushes a signed integer value with the output mode
that is used when printing PVM values.  Valid values are 0 for flat
mode, and 1 for tree mode.

   Stack: '( -- INT )'


File: poke.info,  Node: Instruction popom,  Next: Instruction pushoo,  Prev: Instruction pushom,  Up: VM instructions

22.1.1.8 Instruction popom
..........................

Synopsys:

     popom

   Pop and set output mode.

   This instructions pops a signed integer from the stack and uses it to
set the new output mode to be used when printing PVM values.  Valid
values are 0 for flat mode and 1 for tree mode.

   If an invalid omode is specified then this instruction raises
PVM_E_INVAL.

   Stack: '( INT -- )'

   Exceptions: 'PVM_E_INVAL'


File: poke.info,  Node: Instruction pushoo,  Next: Instruction popoo,  Prev: Instruction popom,  Up: VM instructions

22.1.1.9 Instruction pushoo
...........................

Synopsys:

     pushoo

   Push output offsets mode.

   This instruction pushes a boolean encoded in a signed integer value
indicating whether to show offsets when printing PVM values.

   Stack: '( -- INT )'


File: poke.info,  Node: Instruction popoo,  Next: Instruction pushoi,  Prev: Instruction pushoo,  Up: VM instructions

22.1.1.10 Instruction popoo
...........................

Synopsys:

     popoo

   Pop and set output offsets mode.

   This instructions pops a boolean encoded in a signed integer from the
stack and uses it to set the new output offset mode to be used when
printing PVM values.

   Stack: '( INT -- )'


File: poke.info,  Node: Instruction pushoi,  Next: Instruction popoi,  Prev: Instruction popoo,  Up: VM instructions

22.1.1.11 Instruction pushoi
............................

Synopsys:

     pushoi

   Push output indentation mode.

   This instructions pushes an integer to the stack with the current
indentation step configured in the VM. The indentation step determines
how many white characters to use in each indentation level when printing
output.

   Stack: '( -- INT )'


File: poke.info,  Node: Instruction popoi,  Next: Instruction pushod,  Prev: Instruction pushoi,  Up: VM instructions

22.1.1.12 Instruction popoi
...........................

Synopsys:

     popoi

   Pop and set output indentation step mode.

   This instructions pops an integer from the stack and uses it to set
the current indentation step in the VM. The indentation step determines
how many white characters to use in each indentation level when printing
output.

   Stack: '( INT -- )'


File: poke.info,  Node: Instruction pushod,  Next: Instruction popod,  Prev: Instruction popoi,  Up: VM instructions

22.1.1.13 Instruction pushod
............................

Synopsys:

     pushod

   Push output depth.

   This instruction pushes a signed integer indicating the depth to use
when printing PVM values.

   Stack: '( -- INT )'


File: poke.info,  Node: Instruction popod,  Next: Instruction pushoac,  Prev: Instruction pushod,  Up: VM instructions

22.1.1.14 Instruction popod
...........................

Synopsys:

     popod

   Pop and set output depth.

   This instructions pops a signed integer indicating the maximum depth
included by the VM when printing values.

   Stack: '( INT -- )'


File: poke.info,  Node: Instruction pushoac,  Next: Instruction popoac,  Prev: Instruction popod,  Up: VM instructions

22.1.1.15 Instruction pushoac
.............................

Synopsys:

     pushoac

   Push output array cutoff.

   This instruction pushes a signed integer indicating the number of
elements that the VM includes in the printed representation of PVM array
values.

   Stack: '( -- INT )'


File: poke.info,  Node: Instruction popoac,  Next: Instruction pushopp,  Prev: Instruction pushoac,  Up: VM instructions

22.1.1.16 Instruction popoac
............................

Synopsys:

     popoac

   Pop and set output array cutoff.

   This instructions pops a signed integer indicating the number of
elements that the VM includes in the printed representation of PVM array
values.

   Stack: '( INT -- )'


File: poke.info,  Node: Instruction pushopp,  Next: Instruction popopp,  Prev: Instruction popoac,  Up: VM instructions

22.1.1.17 Instruction pushopp
.............................

Synopsys:

     pushopp

   Push pretty-print usage.

   This instruction pushes a signed integer indicating whether the VM is
configured to use pretty-printers.

   Stack: '( -- INT )'


File: poke.info,  Node: Instruction popopp,  Next: Instruction pushoc,  Prev: Instruction pushopp,  Up: VM instructions

22.1.1.18 Instruction popopp
............................

Synopsys:

     popopp

   Pop and set usage of pretty-printers.

   This instructions pops a signed integer indicating whether to use
pretty-printers when printing values and sets it in the VM.

   Stack: '( INT -- )'


File: poke.info,  Node: Instruction pushoc,  Next: Instruction popoc,  Prev: Instruction popopp,  Up: VM instructions

22.1.1.19 Instruction pushoc
............................

Synopsys:

     pushoc

   Push the current output color to the stack, encoded as a RGB triplet.

   Stack: '( -- INT INT INT )'


File: poke.info,  Node: Instruction popoc,  Next: Instruction pushobc,  Prev: Instruction pushoc,  Up: VM instructions

22.1.1.20 Instruction popoc
...........................

Synopsys:

     popoc

   Pop the RGB triplet at the top of the stack and use it to set the new
terminal output color.

   Stack: '( INT INT INT -- )'


File: poke.info,  Node: Instruction pushobc,  Next: Instruction popobc,  Prev: Instruction popoc,  Up: VM instructions

22.1.1.21 Instruction pushobc
.............................

Synopsys:

     pushobc

   Push the current output background color to the stack, encoded as a
RGB triplet.

   Stack: '( -- INT INT INT )'


File: poke.info,  Node: Instruction popobc,  Next: Instruction sync,  Prev: Instruction pushobc,  Up: VM instructions

22.1.1.22 Instruction popobc
............................

Synopsys:

     popobc

   Pop the RGB triplet at the top of the stack and use it to set the new
terminal output background color.

   Stack: '( INT INT INT -- )'


File: poke.info,  Node: Instruction sync,  Next: Instruction pusharem,  Prev: Instruction popobc,  Up: VM instructions

22.1.1.23 Instruction sync
..........................

Synopsys:

     sync

   Handle pending signals, and raise exceptions accordingly.  This
instruction should be emitted in strategic places, such as before
backwards jumps and at function prolog, to assure signals are eventually
attended to.

   Stack: '( -- )'

   Exceptions: 'PVM_E_SIGNAL'


File: poke.info,  Node: Instruction pusharem,  Next: Instruction poparem,  Prev: Instruction sync,  Up: VM instructions

22.1.1.24 Instruction pusharem
..............................

Synopsys:

     pusharem

   Push autoremap flag.

   This instruction pushes a signed integer indicating whether the VM is
in 'autoremap' mode.

   Stack: '( -- INT )'


File: poke.info,  Node: Instruction poparem,  Prev: Instruction pusharem,  Up: VM instructions

22.1.1.25 Instruction poparem
.............................

Synopsys:

     poparem

   Pop and set the autoremap flag.

   This instruction pops a signed integer from the stack and sets it as
the new value of the 'autoremap' flag.

   Stack: '( INT -- )'


File: poke.info,  Node: IOS related instructions,  Next: Function management instructions,  Prev: VM instructions,  Up: PVM Instructions

22.1.2 IOS related instructions
-------------------------------

* Menu:

* Instruction open::
* Instruction close::
* Instruction flush::
* Instruction pushios::
* Instruction popios::
* Instruction ioflags::
* Instruction iosize::
* Instruction ionum::
* Instruction ioref::
* Instruction iohandler::
* Instruction iogetb::
* Instruction iosetb::


File: poke.info,  Node: Instruction open,  Next: Instruction close,  Up: IOS related instructions

22.1.2.1 Instruction open
.........................

Synopsys:

     open

   Open a new IO space.  The handler string and a set of flags are
passed on the stack.  The descriptor of the opened IOS is pushed to the
stack as a signed integer.

   If there is no other IO space opened when this instruction is
executed, then the just opened space becomes the current IO space.

   If there is an error condition opening the IO space, a negative
number indicating the condition is pushed on the stack.  Note that valid
IOS descriptors are non-negative.  The possible error conditions are:

   -1 for an unspecified error condition.  -3 invalid flags specified -4
memory allocation failure.  -5 end of file -6 invalid argument passed to
open -7 IO space already opened -8 Insufficient permissions to perform
the requested operation.

   Stack: '( STR ULONG -- INT )'


File: poke.info,  Node: Instruction close,  Next: Instruction flush,  Prev: Instruction open,  Up: IOS related instructions

22.1.2.2 Instruction close
..........................

Synopsys:

     close

   Close an IO space.  The descriptor of the space to close is provided
on the stack as a signed integer.

   If the specified IO space doesn't exist, this instruction raises
PVM_E_NO_IOS. If the operation fails, it raises PVM_E_IO.

   Stack: '( INT -- )'

   Exceptions: 'PVM_E_NO_IOS, PVM_E_IO'


File: poke.info,  Node: Instruction flush,  Next: Instruction pushios,  Prev: Instruction close,  Up: IOS related instructions

22.1.2.3 Instruction flush
..........................

Synopsys:

     flush

   Flush an IO space.  The descriptor of the space to flush, and the
bit-offset up to which perform the flushing are provided on the stack.

   If the specified IO space doesn't exist, this instruction raises
PVM_E_IO.

   Stack: '( INT ULONG -- )'

   Exceptions: 'PVM_E_IO'


File: poke.info,  Node: Instruction pushios,  Next: Instruction popios,  Prev: Instruction flush,  Up: IOS related instructions

22.1.2.4 Instruction pushios
............................

Synopsys:

     pushios

   Push the descriptor of the current IO space on the stack, as a signed
integer.  If no IO space is currently opened, push a negative number.

   Stack: '( -- INT )'


File: poke.info,  Node: Instruction popios,  Next: Instruction ioflags,  Prev: Instruction pushios,  Up: IOS related instructions

22.1.2.5 Instruction popios
...........................

Synopsys:

     popios

   Pop an IO space descriptor from the stack and set it as the current
IO space.  If the specified descriptor doesn't identify an IO space,
raise PVM_E_NO_IOS.

   Stack: '( INT -- )'

   Exceptions: 'PVM_E_NO_IOS'


File: poke.info,  Node: Instruction ioflags,  Next: Instruction iosize,  Prev: Instruction popios,  Up: IOS related instructions

22.1.2.6 Instruction ioflags
............................

Synopsys:

     ioflags

   Push an unsigned 64-bit integer with the flags of the given IO space
on the stack.  The IO space is identified by a descriptor, which is a
signed integer.  If the given IO space doesn't exist, raise
PVM_E_NO_IOS.

   Stack: '( INT -- INT ULONG )'

   Exceptions: 'PVM_E_NO_IOS'


File: poke.info,  Node: Instruction iosize,  Next: Instruction ionum,  Prev: Instruction ioflags,  Up: IOS related instructions

22.1.2.7 Instruction iosize
...........................

Synopsys:

     iosize

   Push the size of the given IO space on the stack, as an offset.  The
IO space is identified by a descriptor, which is a signed integer.  If
the given IO space doesn't exist, raise PVM_E_NO_IOS.

   Stack: '( INT -- INT OFF )'

   Exceptions: 'PVM_E_NO_IOS'


File: poke.info,  Node: Instruction ionum,  Next: Instruction ioref,  Prev: Instruction iosize,  Up: IOS related instructions

22.1.2.8 Instruction ionum
..........................

Synopsys:

     ionum

   Pushe the number of IO spaces on the stack.

   Stack: '( -- ULONG )'


File: poke.info,  Node: Instruction ioref,  Next: Instruction iohandler,  Prev: Instruction ionum,  Up: IOS related instructions

22.1.2.9 Instruction ioref
..........................

Synopsys:

     ioref

   Given an index ULONG, push the descriptor of the IO space on the
stack as a signed integer.

   If the provided index is out of bounds, then raise
PVM_E_OUT_OF_BOUNDS.

   Stack: '( ULONG -- ULONG IOS )'

   Exceptions: 'PVM_E_OUT_OF_BOUNDS'


File: poke.info,  Node: Instruction iohandler,  Next: Instruction iogetb,  Prev: Instruction ioref,  Up: IOS related instructions

22.1.2.10 Instruction iohandler
...............................

Synopsys:

     iohandler

   Push the handler of the given IO space on the stack, as a string.
The IO space is identified by a descriptor, which is a signed integer.
If the given IO space doesn't exist, raise PVM_E_NO_IOS.

   Stack: '( INT -- INT OFF )'

   Exceptions: 'PVM_E_NO_IOS'


File: poke.info,  Node: Instruction iogetb,  Next: Instruction iosetb,  Prev: Instruction iohandler,  Up: IOS related instructions

22.1.2.11 Instruction iogetb
............................

Synopsys:

     iogetb

   Each IO space has a bias associated with it, which by default is 0
bits.  This bias is applied to the offset given to every read/write
operation.

   This instruction pushes the bias associated to the given IO space to
the stack, as an offset.  If the given IO space doesn't exist then the
exception PVM_E_NO_IOS is raised.

   Stack: '( INT - INT OFF )'

   Exceptions: 'PVM_E_NO_IOS'


File: poke.info,  Node: Instruction iosetb,  Prev: Instruction iogetb,  Up: IOS related instructions

22.1.2.12 Instruction iosetb
............................

Synopsys:

     iosetb

   Each IO space has a bias associated with it, which by default is 0
bits.  This bias is applied to the offset given to every read/write
operation.

   This instruction sets the bias associated to the given IO space.  The
bias is specified as an offset.  If the given IO space doesn't exist,
the exception PVM_E_NO_IOS is raised.

   Stack: '( OFF INT -- OFF )'

   Exceptions: 'PVM_E_NO_IOS'


File: poke.info,  Node: Function management instructions,  Next: Environment instructions,  Prev: IOS related instructions,  Up: PVM Instructions

22.1.3 Function management instructions
---------------------------------------

* Menu:

* Instruction call::
* Instruction prolog::
* Instruction return::


File: poke.info,  Node: Instruction call,  Next: Instruction prolog,  Up: Function management instructions

22.1.3.1 Instruction call
.........................

Synopsys:

     call

   Call a closure on the stack, passing the specified arguments.  After
the execution of the closure, control is transferred to the instruction
immediately following the call instruction.

   Stack: '( ARG1 ... ARGN CLOSURE -- RETVAL )'


File: poke.info,  Node: Instruction prolog,  Next: Instruction return,  Prev: Instruction call,  Up: Function management instructions

22.1.3.2 Instruction prolog
...........................

Synopsys:

     prolog

   Prepare the PVM for the execution of a function.  This instruction
shall be the target of every 'call' instruction and shall be the first
instruction in every function body.

   Stack: '( -- )'


File: poke.info,  Node: Instruction return,  Prev: Instruction prolog,  Up: Function management instructions

22.1.3.3 Instruction return
...........................

Synopsys:

     return

   Return from a function.  A function can have many 'return'
instructions.

   Stack: '( -- )'


File: poke.info,  Node: Environment instructions,  Next: Printing Instructions,  Prev: Function management instructions,  Up: PVM Instructions

22.1.4 Environment instructions
-------------------------------

* Menu:

* Instruction pushf::
* Instruction popf::
* Instruction pushvar::
* Instruction pushtopvar::
* Instruction popvar::
* Instruction regvar::
* Instruction duc::
* Instruction pec::


File: poke.info,  Node: Instruction pushf,  Next: Instruction popf,  Up: Environment instructions

22.1.4.1 Instruction pushf
..........................

Synopsys:

     pushf N

   Push a new lexical frame.  If the argument N is bigger than zero, it
indicates the number of entries in the frame.  If N is 0, it means we
don't know how many entries will be stored in the frame.

   Stack: '( -- )'


File: poke.info,  Node: Instruction popf,  Next: Instruction pushvar,  Prev: Instruction pushf,  Up: Environment instructions

22.1.4.2 Instruction popf
.........................

Synopsys:

     popf N

   Pop N lexical frames.

   Stack: '( -- )'


File: poke.info,  Node: Instruction pushvar,  Next: Instruction pushtopvar,  Prev: Instruction popf,  Up: Environment instructions

22.1.4.3 Instruction pushvar
............................

Synopsys:

     pushvar BACK, OVER

   Retrieve the value of a variable from the lexical environment and
push it on the stack.  The lexical address of the variable is specified
as arguments to the instruction.

   Stack: '( -- VAL )'


File: poke.info,  Node: Instruction pushtopvar,  Next: Instruction popvar,  Prev: Instruction pushvar,  Up: Environment instructions

22.1.4.4 Instruction pushtopvar
...............................

Synopsys:

     pushtopvar OVER

   Retrieve the value of a variable from the top-level frame of the
lexical environment and put it on the stack.  The OVER part of the
lexical address of the variable is specified as an argument to the
instruction.

   If the variable is not found then raise E_INVAL.

   Stack: '( -- VAL )'


File: poke.info,  Node: Instruction popvar,  Next: Instruction regvar,  Prev: Instruction pushtopvar,  Up: Environment instructions

22.1.4.5 Instruction popvar
...........................

Synopsys:

     popvar BACK, OVER

   Pop a value from the stack and set it as the value of a variable
having the lexical address specified in the arguments, in the current
lexical environment.

   Stack: '( VAL -- )'


File: poke.info,  Node: Instruction regvar,  Next: Instruction duc,  Prev: Instruction popvar,  Up: Environment instructions

22.1.4.6 Instruction regvar
...........................

Synopsys:

     regvar

   Pop a value from the stack and use it as the value for a new variable
in the current lexical environment.

   Stack: '( VAL -- )'


File: poke.info,  Node: Instruction duc,  Next: Instruction pec,  Prev: Instruction regvar,  Up: Environment instructions

22.1.4.7 Instruction duc
........................

Synopsys:

     duc

   Make a copy of the closure at the top of the stack, and replace it.

   Stack: '( CLS -- CLS )'


File: poke.info,  Node: Instruction pec,  Prev: Instruction duc,  Up: Environment instructions

22.1.4.8 Instruction pec
........................

Synopsys:

     pec

   Put the current lexical environment to the closure at the top of the
stack.

   Stack: '( CLS -- CLS )'


File: poke.info,  Node: Printing Instructions,  Next: Format Instructions,  Prev: Environment instructions,  Up: PVM Instructions

22.1.5 Printing Instructions
----------------------------

* Menu:

* Instruction printi::
* Instruction printiu::
* Instruction printl::
* Instruction printlu::
* Instruction prints::
* Instruction beghl::
* Instruction endhl::
* Instruction begsc::
* Instruction endsc::

In the following instructions the meaning of the argument BASE is the
following:

   2 - print the number in binary.  8 - print the number in octal.  16 -
print the number in hexadecimal.  Any other value - print the number in
decimal.


File: poke.info,  Node: Instruction printi,  Next: Instruction printiu,  Up: Printing Instructions

22.1.5.1 Instruction printi
...........................

Synopsys:

     printi BITS

   Given a signed integer and a numeration base in the stack, print the
integer to the terminal.

   Stack: '( INT INT -- )'


File: poke.info,  Node: Instruction printiu,  Next: Instruction printl,  Prev: Instruction printi,  Up: Printing Instructions

22.1.5.2 Instruction printiu
............................

Synopsys:

     printiu BITS

   Given an unsigned integer and a numeration base in the stack, print
the integer to the terminal.

   Stack: '( UINT INT -- )'


File: poke.info,  Node: Instruction printl,  Next: Instruction printlu,  Prev: Instruction printiu,  Up: Printing Instructions

22.1.5.3 Instruction printl
...........................

Synopsys:

     printl BITS

   Given a long and a numeration base in the stack, print the integer to
the terminal.

   Stack: '( LONG INT -- )'


File: poke.info,  Node: Instruction printlu,  Next: Instruction prints,  Prev: Instruction printl,  Up: Printing Instructions

22.1.5.4 Instruction printlu
............................

Synopsys:

     printlu BITS

   Given an unsigned long and a numeration base in the stack, print the
integer to the terminal.

   Stack: '( ULONG INT -- )'


File: poke.info,  Node: Instruction prints,  Next: Instruction beghl,  Prev: Instruction printlu,  Up: Printing Instructions

22.1.5.5 Instruction prints
...........................

Synopsys:

     prints

   Print the string at the top of the stack.

   Stack: '( STR -- )'


File: poke.info,  Node: Instruction beghl,  Next: Instruction endhl,  Prev: Instruction prints,  Up: Printing Instructions

22.1.5.6 Instruction beghl
..........................

Synopsys:

     beghl

   Begin an hyperlink, using the URL and ID on the stack.

   Stack: '( STR STR -- )'


File: poke.info,  Node: Instruction endhl,  Next: Instruction begsc,  Prev: Instruction beghl,  Up: Printing Instructions

22.1.5.7 Instruction endhl
..........................

Synopsys:

     endhl

   End the current hyperlink.

   If no hyperlink is currently being generated, this instruction raises
an exception.

   Stack: '( -- )'

   Exceptions: 'PVM_E_GENERIC'


File: poke.info,  Node: Instruction begsc,  Next: Instruction endsc,  Prev: Instruction endhl,  Up: Printing Instructions

22.1.5.8 Instruction begsc
..........................

Synopsys:

     begsc

   Begin the styling class whose name is found on the stack.  This class
will be in effect in subsequent print operations until it is explicitly
ended by a 'endsc' instruction.

   Stack: '( STR -- )'


File: poke.info,  Node: Instruction endsc,  Prev: Instruction begsc,  Up: Printing Instructions

22.1.5.9 Instruction endsc
..........................

Synopsys:

     endsc

   End the styling class whose name is found on the stack.  This class
should have been previously began by a 'begsc' instruction.

   Stack: '( STR -- )'


File: poke.info,  Node: Format Instructions,  Next: Main stack manipulation instructions,  Prev: Printing Instructions,  Up: PVM Instructions

22.1.6 Format Instructions
--------------------------

* Menu:

* Instruction formati::
* Instruction formatiu::
* Instruction formatl::
* Instruction formatlu::
* Instruction formatf32::
* Instruction formatf64::

In the following instructions the meaning of the argument BASE is the
following:

   2 - format the number in binary.  8 - format the number in octal.  16
- format the number in hexadecimal.  Any other value - format the number
in decimal.


File: poke.info,  Node: Instruction formati,  Next: Instruction formatiu,  Up: Format Instructions

22.1.6.1 Instruction formati
............................

Synopsys:

     formati BITS

   Given a signed integer and a numeration base in the stack, push the
string representation to the stack.

   Stack: '( INT INT -- STR )'


File: poke.info,  Node: Instruction formatiu,  Next: Instruction formatl,  Prev: Instruction formati,  Up: Format Instructions

22.1.6.2 Instruction formatiu
.............................

Synopsys:

     formatiu BITS

   Given an unsigned integer and a numeration base in the stack, push
the string representation to the stack.

   Stack: '( UINT INT -- STR )'


File: poke.info,  Node: Instruction formatl,  Next: Instruction formatlu,  Prev: Instruction formatiu,  Up: Format Instructions

22.1.6.3 Instruction formatl
............................

Synopsys:

     formatl BITS

   Given a long and a numeration base in the stack, push the string
representation to the stack.

   Stack: '( LONG INT -- STR )'


File: poke.info,  Node: Instruction formatlu,  Next: Instruction formatf32,  Prev: Instruction formatl,  Up: Format Instructions

22.1.6.4 Instruction formatlu
.............................

Synopsys:

     formatlu BITS

   Given an unsigned long and a numeration base in the stack, push the
string representation to the stack.

   Stack: '( ULONG INT -- STR )'


File: poke.info,  Node: Instruction formatf32,  Next: Instruction formatf64,  Prev: Instruction formatlu,  Up: Format Instructions

22.1.6.5 Instruction formatf32
..............................

Synopsys:

     formatf32 STYLE

   Given a UINT (that should be interpreted as a 32-bit floating-point
number), and a UINT (as the conversion precision), push the string
representation of the floating-point number with specified precision.

   The formatting style is given by a literal parameters.  Style 0
corresponds to %f-tag which converts the number in the style [-]ddd.ddd
where the number of digits after the decimal-point character is the
equal to the precision.  Style 1 corresponds to %e-tag which converts
the number in the style [-]d.ddde+-dd (so called scientific notation).
Precision for this style also means the number of digits after the
decimal-point character.  Style 2 corresponds to %g-tag which choose
either %f style or %e based on the length of the repsentation.  For this
style, precision specify the number of significant numbers.

   Stack: '( UINT UINT -- STR )'


File: poke.info,  Node: Instruction formatf64,  Prev: Instruction formatf32,  Up: Format Instructions

22.1.6.6 Instruction formatf64
..............................

Synopsys:

     formatf64 STYLE

   Given a ULONG (that should be interpreted as a 64-bit floating-point
number), and a UINT (as the conversion precision), push the string
representation of the floating-point number with specified precision.
The formatting style is given by a literal parameters.

   The formatting style is given by a literal parameters.  Style 0
corresponds to %f-tag which converts the number in the style [-]ddd.ddd
where the number of digits after the decimal-point character is the
equal to the precision.  Style 1 corresponds to %e-tag which converts
the number in the style [-]d.ddde+-dd (so called scientific notation).
Precision for this style also means the number of digits after the
decimal-point character.  Style 2 corresponds to %g-tag which choose
either %f style or %e based on the length of the repsentation.  For this
style, precision specify the number of significant numbers.

   Stack: '( ULONG UINT -- STR )'


File: poke.info,  Node: Main stack manipulation instructions,  Next: Registers manipulation instructions,  Prev: Format Instructions,  Up: PVM Instructions

22.1.7 Main stack manipulation instructions
-------------------------------------------

* Menu:

* Instruction push::
* Instruction drop::
* Instruction drop2::
* Instruction drop3::
* Instruction drop4::
* Instruction swap::
* Instruction nip::
* Instruction nip2::
* Instruction nip3::
* Instruction dup::
* Instruction over::
* Instruction oover::
* Instruction rot::
* Instruction nrot::
* Instruction tuck::
* Instruction quake::
* Instruction revn::
* Instruction pushhi::
* Instruction pushlo::
* Instruction push32::


File: poke.info,  Node: Instruction push,  Next: Instruction drop,  Up: Main stack manipulation instructions

22.1.7.1 Instruction push
.........................

Synopsys:

     push VAL

   Push the value given as an argument to the main stack.

   Stack: '( -- VAL )'


File: poke.info,  Node: Instruction drop,  Next: Instruction drop2,  Prev: Instruction push,  Up: Main stack manipulation instructions

22.1.7.2 Instruction drop
.........................

Synopsys:

     drop

   Pop the value at the top of the main stack, and discard it.

   Stack: '( VAL -- )'


File: poke.info,  Node: Instruction drop2,  Next: Instruction drop3,  Prev: Instruction drop,  Up: Main stack manipulation instructions

22.1.7.3 Instruction drop2
..........................

Synopsys:

     drop2

   Pop the two values at the top of the main stack, and discard them.

   Stack: '( VAL VAL -- )'


File: poke.info,  Node: Instruction drop3,  Next: Instruction drop4,  Prev: Instruction drop2,  Up: Main stack manipulation instructions

22.1.7.4 Instruction drop3
..........................

Synopsys:

     drop3

   Pop the three values at the top of the main stack, and discard them.

   Stack: '( VAL VAL VAL -- )'


File: poke.info,  Node: Instruction drop4,  Next: Instruction swap,  Prev: Instruction drop3,  Up: Main stack manipulation instructions

22.1.7.5 Instruction drop4
..........................

Synopsys:

     drop4

   Pop the four values at the top of the stack, and discard them.

   Stack: '( VAL VAL VAL VAL -- )'


File: poke.info,  Node: Instruction swap,  Next: Instruction nip,  Prev: Instruction drop4,  Up: Main stack manipulation instructions

22.1.7.6 Instruction swap
.........................

Synopsys:

     swap

   Exchange the two elements at the top of the stack.

   Stack: '( A B -- B A)'


File: poke.info,  Node: Instruction nip,  Next: Instruction nip2,  Prev: Instruction swap,  Up: Main stack manipulation instructions

22.1.7.7 Instruction nip
........................

Synopsys:

     nip

   Discard the element at the under top of the main stack.

   Stack: '( A B -- B )'


File: poke.info,  Node: Instruction nip2,  Next: Instruction nip3,  Prev: Instruction nip,  Up: Main stack manipulation instructions

22.1.7.8 Instruction nip2
.........................

Synopsys:

     nip2

   Discard the two elements at the under top of the main stack.

   Stack: '( A B C -- C )'


File: poke.info,  Node: Instruction nip3,  Next: Instruction dup,  Prev: Instruction nip2,  Up: Main stack manipulation instructions

22.1.7.9 Instruction nip3
.........................

Synopsys:

     nip3

   Discard the three elements at the under top of the main stack.

   Stack: '( A B C D -- D )'


File: poke.info,  Node: Instruction dup,  Next: Instruction over,  Prev: Instruction nip3,  Up: Main stack manipulation instructions

22.1.7.10 Instruction dup
.........................

Synopsys:

     dup

   Push a copy of the element at the top of the main stack.

   Stack: '( A -- A A )'


File: poke.info,  Node: Instruction over,  Next: Instruction oover,  Prev: Instruction dup,  Up: Main stack manipulation instructions

22.1.7.11 Instruction over
..........................

Synopsys:

     over

   Push a copy of the element at the under top of the main stack.

   Stack: '( A B -- A B A )'


File: poke.info,  Node: Instruction oover,  Next: Instruction rot,  Prev: Instruction over,  Up: Main stack manipulation instructions

22.1.7.12 Instruction oover
...........................

Synopsys:

     oover

   Push a copy of the element under the under top of the main stack.

   Stack: '( A B C -- A B C A )'


File: poke.info,  Node: Instruction rot,  Next: Instruction nrot,  Prev: Instruction oover,  Up: Main stack manipulation instructions

22.1.7.13 Instruction rot
.........................

Synopsys:

     rot

   Rotate the three elements at the top of the main stack, clock-wise.

   Stack: '( A B C -- B C A )'


File: poke.info,  Node: Instruction nrot,  Next: Instruction tuck,  Prev: Instruction rot,  Up: Main stack manipulation instructions

22.1.7.14 Instruction nrot
..........................

Synopsys:

     nrot

   Rotate the three elements at the top of the stack, counter
clock-wise.

   Stack: '( A B C -- C A B )'


File: poke.info,  Node: Instruction tuck,  Next: Instruction quake,  Prev: Instruction nrot,  Up: Main stack manipulation instructions

22.1.7.15 Instruction tuck
..........................

Synopsys:

     tuck

   Tuck a copy of the element at the top of the stack down two
positions.

   Stack: '( A B -- B A B )'


File: poke.info,  Node: Instruction quake,  Next: Instruction revn,  Prev: Instruction tuck,  Up: Main stack manipulation instructions

22.1.7.16 Instruction quake
...........................

Synopsys:

     quake

   Swap the two elements at the under top of the stack.

   Stack: '( A B C - B A C )'


File: poke.info,  Node: Instruction revn,  Next: Instruction pushhi,  Prev: Instruction quake,  Up: Main stack manipulation instructions

22.1.7.17 Instruction revn
..........................

Synopsys:

     revn N

   Reverse the N elements at the top of the stack.

   Stack: '( VAL... -- VAL... )'


File: poke.info,  Node: Instruction pushhi,  Next: Instruction pushlo,  Prev: Instruction revn,  Up: Main stack manipulation instructions

22.1.7.18 Instruction pushhi
............................

Synopsys:

     pushhi VAL

   Push the high 32 bits of the value passed as an argument to the main
stack.  This instruction shall be completed with a 'pushlo'.

   This instruction is a workaround to a limitation of Jitter.

   Stack: '( -- HI32(VAL) )'


File: poke.info,  Node: Instruction pushlo,  Next: Instruction push32,  Prev: Instruction pushhi,  Up: Main stack manipulation instructions

22.1.7.19 Instruction pushlo
............................

Synopsys:

     pushlo VAL

   Push the low 32 bits of the value passed as an argument to the main
stack.  This instruction shall be preceded by a 'pushhi'.

   This instruction is a workaround to a limitation of Jitter.

   Stack: '( -- LO32(VAL) )'


File: poke.info,  Node: Instruction push32,  Prev: Instruction pushlo,  Up: Main stack manipulation instructions

22.1.7.20 Instruction push32
............................

Synopsys:

     push32 VAL

   Push the value passed as an argument on the stack.  This assumes that
the internal representation of VAL doesn't require more than 32-bit.

   This instruction is a workaround to a limitation of Jitter.

   Stack: '( -- VAL )'


File: poke.info,  Node: Registers manipulation instructions,  Next: Return stack manipulation instructions,  Prev: Main stack manipulation instructions,  Up: PVM Instructions

22.1.8 Registers manipulation instructions
------------------------------------------

* Menu:

* Instruction pushr::
* Instruction popr::
* Instruction setr::


File: poke.info,  Node: Instruction pushr,  Next: Instruction popr,  Up: Registers manipulation instructions

22.1.8.1 Instruction pushr
..........................

Synopsys:

     pushr REGNO

   Push the contents of the register REGNO on the stack.

   Stack: '( -- VAL )'


File: poke.info,  Node: Instruction popr,  Next: Instruction setr,  Prev: Instruction pushr,  Up: Registers manipulation instructions

22.1.8.2 Instruction popr
.........................

Synopsys:

     popr REGNO

   Pop the element at the top of the stack and put it in the register
REGNO.

   Stack: '( VAL -- )'


File: poke.info,  Node: Instruction setr,  Prev: Instruction popr,  Up: Registers manipulation instructions

22.1.8.3 Instruction setr
.........................

Synopsys:

     setr REGNO

   Set the element at the top of the stack to the value of the register
REGNO.

   Stack: '( -- )'


File: poke.info,  Node: Return stack manipulation instructions,  Next: Arithmetic instructions,  Prev: Registers manipulation instructions,  Up: PVM Instructions

22.1.9 Return stack manipulation instructions
---------------------------------------------

* Menu:

* Instruction saver::
* Instruction restorer::
* Instruction tor::
* Instruction fromr::
* Instruction atr::


File: poke.info,  Node: Instruction saver,  Next: Instruction restorer,  Up: Return stack manipulation instructions

22.1.9.1 Instruction saver
..........................

Synopsys:

     saver REGNO

   Push the contents of the register REGNO to the return stack.

   Stack: '( -- )' ReturnStack: ( - VAL )


File: poke.info,  Node: Instruction restorer,  Next: Instruction tor,  Prev: Instruction saver,  Up: Return stack manipulation instructions

22.1.9.2 Instruction restorer
.............................

Synopsys:

     restorer REGNO

   Pop the element at the top of the return stack and put it in the
register REGNO.

   Stack: '( -- )' ReturnStack: ( VAL - )


File: poke.info,  Node: Instruction tor,  Next: Instruction fromr,  Prev: Instruction restorer,  Up: Return stack manipulation instructions

22.1.9.3 Instruction tor
........................

Synopsys:

     tor

   Pop an element from the stack and push it in the return stack.

   Stack: '( VAL -- )' ReturnStack: ( - VAL )


File: poke.info,  Node: Instruction fromr,  Next: Instruction atr,  Prev: Instruction tor,  Up: Return stack manipulation instructions

22.1.9.4 Instruction fromr
..........................

Synopsys:

     fromr

   Pop an element from the return stack and push it on the stack.

   Stack: '( -- VAL)' ReturnStack: ( VAL - )


File: poke.info,  Node: Instruction atr,  Prev: Instruction fromr,  Up: Return stack manipulation instructions

22.1.9.5 Instruction atr
........................

Synopsys:

     atr

   Push a copy of the element at the top of the return stack into the
stack.

   Stack: '( -- VAL )'


File: poke.info,  Node: Arithmetic instructions,  Next: Relational instructions,  Prev: Return stack manipulation instructions,  Up: PVM Instructions

22.1.10 Arithmetic instructions
-------------------------------

* Menu:

* Instruction addi::
* Instruction addiu::
* Instruction addlu::
* Instruction subi::
* Instruction subiu::
* Instruction subl::
* Instruction sublu::
* Instruction muli::
* Instruction muliu::
* Instruction mull::
* Instruction mullu::
* Instruction divi::
* Instruction diviu::
* Instruction divl::
* Instruction divlu::
* Instruction modi::
* Instruction modiu::
* Instruction modl::
* Instruction modlu::
* Instruction negi::
* Instruction negiu::
* Instruction negl::
* Instruction neglu::
* Instruction powi::
* Instruction powiu::
* Instruction powl::
* Instruction powlu::

The following instructions assume that both operands have the same size
in bits.


File: poke.info,  Node: Instruction addi,  Next: Instruction addiu,  Up: Arithmetic instructions

22.1.10.1 Instruction addi
..........................

Synopsys:

     addi

   Push the result of adding the two integers at the top of the stack.
If the operation would result in overflow, raise PVM_E_OVERFLOW.

   Stack: '( INT INT -- INT INT INT )'

   Exceptions: 'PVM_E_OVERFLOW'


File: poke.info,  Node: Instruction addiu,  Next: Instruction addlu,  Prev: Instruction addi,  Up: Arithmetic instructions

22.1.10.2 Instruction addiu
...........................

Synopsys:

     addiu

   Push the result of adding the two unsigned integers at the top of the
stack.

   Stack: '( UINT UINT -- UINT UINT UINT )' Instruction addl

   Push the result of adding the two longs at the top of the stack.  If
the operation would result in overflow, raise PVM_E_OVERFLOW.

   Stack: '( LONG LONG -- LONG LONG LONG )'

   Exceptions: 'PVM_E_OVERFLOW'


File: poke.info,  Node: Instruction addlu,  Next: Instruction subi,  Prev: Instruction addiu,  Up: Arithmetic instructions

22.1.10.3 Instruction addlu
...........................

Synopsys:

     addlu

   Push the result of adding the two unsigned longs at the top of the
stack.

   Stack: '( ULONG ULONG -- ULONG ULONG ULONG )'


File: poke.info,  Node: Instruction subi,  Next: Instruction subiu,  Prev: Instruction addlu,  Up: Arithmetic instructions

22.1.10.4 Instruction subi
..........................

Synopsys:

     subi

   Push the result of subtracting the two integers at the top of the
stack.

   Stack: '( INT INT -- INT INT INT )'


File: poke.info,  Node: Instruction subiu,  Next: Instruction subl,  Prev: Instruction subi,  Up: Arithmetic instructions

22.1.10.5 Instruction subiu
...........................

Synopsys:

     subiu

   Push the result of subtracting the two unsigned integers at the top
of the stack.

   Stack: '( UINT UINT -- UINT UINT UINT )'


File: poke.info,  Node: Instruction subl,  Next: Instruction sublu,  Prev: Instruction subiu,  Up: Arithmetic instructions

22.1.10.6 Instruction subl
..........................

Synopsys:

     subl

   Push the result of subtracting the two longs at the top of the stack.

   Stack: '( LONG LONG -- LONG LONG LONG )'


File: poke.info,  Node: Instruction sublu,  Next: Instruction muli,  Prev: Instruction subl,  Up: Arithmetic instructions

22.1.10.7 Instruction sublu
...........................

Synopsys:

     sublu

   Push the result of subtracting the two unsigned longs at the top of
the stack.

   Stack: '( ULONG ULONG -- ULONG ULONG ULONG )'


File: poke.info,  Node: Instruction muli,  Next: Instruction muliu,  Prev: Instruction sublu,  Up: Arithmetic instructions

22.1.10.8 Instruction muli
..........................

Synopsys:

     muli

   Push the result of multiplying the two integers at the top of the
stack.

   Stack: '( INT INT -- INT INT INT )'


File: poke.info,  Node: Instruction muliu,  Next: Instruction mull,  Prev: Instruction muli,  Up: Arithmetic instructions

22.1.10.9 Instruction muliu
...........................

Synopsys:

     muliu

   Push the result of multiplying the two unsigned integers at the top
of the stack.

   Stack: '( UINT UINT -- UINT UINT UINT )'


File: poke.info,  Node: Instruction mull,  Next: Instruction mullu,  Prev: Instruction muliu,  Up: Arithmetic instructions

22.1.10.10 Instruction mull
...........................

Synopsys:

     mull

   Push the result of multiplying the two longs at the top of the stack.

   Stack: '( LONG LONG -- LONG LONG LONG )'


File: poke.info,  Node: Instruction mullu,  Next: Instruction divi,  Prev: Instruction mull,  Up: Arithmetic instructions

22.1.10.11 Instruction mullu
............................

Synopsys:

     mullu

   Push the result of multiplying the two unsigned longs at the top of
the stack.

   Stack: '( ULONG ULONG -- ULONG ULONG ULONG )'


File: poke.info,  Node: Instruction divi,  Next: Instruction diviu,  Prev: Instruction mullu,  Up: Arithmetic instructions

22.1.10.12 Instruction divi
...........................

Synopsys:

     divi

   Push the result of the integer division of the two integers at the
top of the stack.  If the denominator is zero, raise PVM_E_DIV_BY_ZERO.

   Stack: '( INT INT -- INT INT INT )'

   Exceptions: 'PVM_E_DIV_BY_ZERO'


File: poke.info,  Node: Instruction diviu,  Next: Instruction divl,  Prev: Instruction divi,  Up: Arithmetic instructions

22.1.10.13 Instruction diviu
............................

Synopsys:

     diviu

   Push the result of the integer division of the two unsigned integers
at the top of the stack.  If the denominator is zero, raise
PVM_E_DIV_BY_ZERO.

   Stack: '( UINT UINT -- UINT UINT UINT )'

   Exceptions: 'PVM_E_DIV_BY_ZERO'


File: poke.info,  Node: Instruction divl,  Next: Instruction divlu,  Prev: Instruction diviu,  Up: Arithmetic instructions

22.1.10.14 Instruction divl
...........................

Synopsys:

     divl

   Push the result of the integer division of the two longs at the top
of the stack.  If the denominator is zero, raise PVM_E_DIV_BY_ZERO.

   Stack: '( LONG LONG -- LONG LONG LONG )'

   Exceptions: 'PVM_E_DIV_BY_ZERO'


File: poke.info,  Node: Instruction divlu,  Next: Instruction modi,  Prev: Instruction divl,  Up: Arithmetic instructions

22.1.10.15 Instruction divlu
............................

Synopsys:

     divlu

   Push the result of the integer division of the two unsigned longs at
the top of the stack.  If the denominator is zero, raise
PVM_E_DIV_BY_ZERO.

   Stack: '( ULONG ULONG -- ULONG ULONG ULONG )'

   Exceptions: 'PVM_E_DIV_BY_ZERO'


File: poke.info,  Node: Instruction modi,  Next: Instruction modiu,  Prev: Instruction divlu,  Up: Arithmetic instructions

22.1.10.16 Instruction modi
...........................

Synopsys:

     modi

   Push the result of the modulus of the two integers at the top of the
stack.  If the denominator is zero, raise PVM_E_DIV_BY_ZERO.

   Stack: '( INT INT -- INT INT INT )'

   Exceptions: 'PVM_E_DIV_BY_ZERO'


File: poke.info,  Node: Instruction modiu,  Next: Instruction modl,  Prev: Instruction modi,  Up: Arithmetic instructions

22.1.10.17 Instruction modiu
............................

Synopsys:

     modiu

   Push the result of the modulus of the two unsigned integers at the
top of the stack.  If the denominator is zero, raise PVM_E_DIV_BY_ZERO.

   Stack: '( UINT UINT -- UINT UINT UINT )'

   Exceptions: 'PVM_E_DIV_BY_ZERO'


File: poke.info,  Node: Instruction modl,  Next: Instruction modlu,  Prev: Instruction modiu,  Up: Arithmetic instructions

22.1.10.18 Instruction modl
...........................

Synopsys:

     modl

   Push the result of the modulus of the two longs at the top of the
stack.  If the denominator is zero, raise PVM_E_DIV_BY_ZERO.

   Stack: '( LONG LONG -- LONG LONG LONG )'

   Exceptions: 'PVM_E_DIV_BY_ZERO'


File: poke.info,  Node: Instruction modlu,  Next: Instruction negi,  Prev: Instruction modl,  Up: Arithmetic instructions

22.1.10.19 Instruction modlu
............................

Synopsys:

     modlu

   Push the result of the modulus of the two unsigned longs at the top
of the stack.  If the denominator is zero, raise PVM_E_DIV_BY_ZERO.

   Stack: '( ULONG ULONG -- ULONG ULONG ULONG )'

   Exceptions: 'PVM_E_DIV_BY_ZERO'


File: poke.info,  Node: Instruction negi,  Next: Instruction negiu,  Prev: Instruction modlu,  Up: Arithmetic instructions

22.1.10.20 Instruction negi
...........................

Synopsys:

     negi

   Push the result of the negation of the integer at the top of the
stack.

   Stack: '( INT -- INT INT )'


File: poke.info,  Node: Instruction negiu,  Next: Instruction negl,  Prev: Instruction negi,  Up: Arithmetic instructions

22.1.10.21 Instruction negiu
............................

Synopsys:

     negiu

   Push the result of the negation of the unsigned integer at the top of
the stack.

   Stack: '( UINT -- UINT UINT UINT )'


File: poke.info,  Node: Instruction negl,  Next: Instruction neglu,  Prev: Instruction negiu,  Up: Arithmetic instructions

22.1.10.22 Instruction negl
...........................

Synopsys:

     negl

   Push the result of the negation of the long at the top of the stack.

   Stack: '( LONG -- LONG LONG )'


File: poke.info,  Node: Instruction neglu,  Next: Instruction powi,  Prev: Instruction negl,  Up: Arithmetic instructions

22.1.10.23 Instruction neglu
............................

Synopsys:

     neglu

   Push the result of the negation of the unsigned long at the top of
the stack.

   Stack: '( ULONG -- ULONG ULONG )'


File: poke.info,  Node: Instruction powi,  Next: Instruction powiu,  Prev: Instruction neglu,  Up: Arithmetic instructions

22.1.10.24 Instruction powi
...........................

Synopsys:

     powi

   Perform the exponentiation of the integer at the under top of the
stack.  The exponent is the unsigned integer at the top of the stack.
If the exponent is 0, the result is 1.

   Stack: '( INT UINT -- INT UINT INT )'


File: poke.info,  Node: Instruction powiu,  Next: Instruction powl,  Prev: Instruction powi,  Up: Arithmetic instructions

22.1.10.25 Instruction powiu
............................

Synopsys:

     powiu

   Perform the exponentiation of the unsigned integer at the under top
of the stack.  The exponent is the unsigned integer at the top of the
stack.  If the exponent is 0, the result is 1.

   Stack: '( UINT UINT -- UINT UINT UINT )'


File: poke.info,  Node: Instruction powl,  Next: Instruction powlu,  Prev: Instruction powiu,  Up: Arithmetic instructions

22.1.10.26 Instruction powl
...........................

Synopsys:

     powl

   Perform the exponentiation of the long at the under top of the stack.
The exponent is the unsigned integer at the top of the stack.  If the
exponent is 0, the result is 1.

   Stack: '( LONG UINT -- LONG UINT LONG )'


File: poke.info,  Node: Instruction powlu,  Prev: Instruction powl,  Up: Arithmetic instructions

22.1.10.27 Instruction powlu
............................

Synopsys:

     powlu

   Perform the exponentiation of the unsigned long at the under top of
the stack.  The exponent is the unsigned integer at the top of the
stack.  If the exponent is 0, the result is 1.

   Stack: '( ULONG UINT -- ULONG UINT ULONG )'


File: poke.info,  Node: Relational instructions,  Next: Concatenation instructions,  Prev: Arithmetic instructions,  Up: PVM Instructions

22.1.11 Relational instructions
-------------------------------

* Menu:

* Instruction eqi::
* Instruction eqiu::
* Instruction eql::
* Instruction eqlu::
* Instruction eqs::
* Instruction nei::
* Instruction neiu::
* Instruction nel::
* Instruction nelu::
* Instruction nes::
* Instruction nn::
* Instruction nnn::
* Instruction lti::
* Instruction ltiu::
* Instruction ltl::
* Instruction ltlu::
* Instruction lei::
* Instruction leiu::
* Instruction lel::
* Instruction lelu::
* Instruction gti::
* Instruction gtiu::
* Instruction gtl::
* Instruction gtlu::
* Instruction gei::
* Instruction geiu::
* Instruction gel::
* Instruction gelu::
* Instruction lts::
* Instruction gts::
* Instruction ges::
* Instruction les::
* Instruction eqc::
* Instruction nec::


File: poke.info,  Node: Instruction eqi,  Next: Instruction eqiu,  Up: Relational instructions

22.1.11.1 Instruction eqi
.........................

Synopsys:

     eqi

   Push 1 on the stack if the two integers at the top of the stack are
equal.  Otherwise push 0.

   Stack: '( INT INT -- INT INT INT )'


File: poke.info,  Node: Instruction eqiu,  Next: Instruction eql,  Prev: Instruction eqi,  Up: Relational instructions

22.1.11.2 Instruction eqiu
..........................

Synopsys:

     eqiu

   Push 1 on the stack if the two unsigned integers at the top of the
stack are equal.  Otherwise push 0.

   Stack: '( UINT UINT -- UINT UINT UINT )'


File: poke.info,  Node: Instruction eql,  Next: Instruction eqlu,  Prev: Instruction eqiu,  Up: Relational instructions

22.1.11.3 Instruction eql
.........................

Synopsys:

     eql

   Push 1 on the stack if the two longs at the top of the stack are
equal.  Otherwise push 0.

   Stack: '( LONG LONG -- LONG LONG INT )'


File: poke.info,  Node: Instruction eqlu,  Next: Instruction eqs,  Prev: Instruction eql,  Up: Relational instructions

22.1.11.4 Instruction eqlu
..........................

Synopsys:

     eqlu

   Push 1 on the stack if the two unsigned longs at the top of the stack
are equal.  Otherwise push 0.

   Stack: '( ULONG ULONG -- ULONG ULONG INT )'


File: poke.info,  Node: Instruction eqs,  Next: Instruction nei,  Prev: Instruction eqlu,  Up: Relational instructions

22.1.11.5 Instruction eqs
.........................

Synopsys:

     eqs

   Push 1 on the stack if the two strings at the top of the stack are
equal.  Otherwise push 0.

   Stack: '( STR STR -- STR STR INT )'


File: poke.info,  Node: Instruction nei,  Next: Instruction neiu,  Prev: Instruction eqs,  Up: Relational instructions

22.1.11.6 Instruction nei
.........................

Synopsys:

     nei

   Push 1 on the stack if the two integers at the top of the stack are
not equal.  Otherwise push 0.

   Stack: '( INT INT -- INT INT INT )'


File: poke.info,  Node: Instruction neiu,  Next: Instruction nel,  Prev: Instruction nei,  Up: Relational instructions

22.1.11.7 Instruction neiu
..........................

Synopsys:

     neiu

   Push 1 on the stack if the two unsigned integers at the top of the
stack are not equal.  Otherwise push 0.

   Stack: '( UINT UINT -- UINT UINT INT )'


File: poke.info,  Node: Instruction nel,  Next: Instruction nelu,  Prev: Instruction neiu,  Up: Relational instructions

22.1.11.8 Instruction nel
.........................

Synopsys:

     nel

   Push 1 on the stack if the two longs at the top of the stack are not
equal.  Otherwise push 0.

   Stack: '( LONG LONG -- LONG LONG INT )'


File: poke.info,  Node: Instruction nelu,  Next: Instruction nes,  Prev: Instruction nel,  Up: Relational instructions

22.1.11.9 Instruction nelu
..........................

Synopsys:

     nelu

   Push 1 on the stack if the two unsigned longs at the top of the stack
are not equal.  Otherwise push 0.

   Stack: '( ULONG ULONG -- ULONG ULONG INT )'


File: poke.info,  Node: Instruction nes,  Next: Instruction nn,  Prev: Instruction nelu,  Up: Relational instructions

22.1.11.10 Instruction nes
..........................

Synopsys:

     nes

   Push 1 on the stack if the two strings at the top of the stack are
not equal.  Otherwise push 0.

   Stack: '( STR STR -- STR STR INT )'


File: poke.info,  Node: Instruction nn,  Next: Instruction nnn,  Prev: Instruction nes,  Up: Relational instructions

22.1.11.11 Instruction nn
.........................

Synopsys:

     nn

   Push 0 on the stack if the value at the top of the stack equals
PVM_NULL. Otherwise push 1.

   Stack: '( VAL -- VAL INT )'


File: poke.info,  Node: Instruction nnn,  Next: Instruction lti,  Prev: Instruction nn,  Up: Relational instructions

22.1.11.12 Instruction nnn
..........................

Synopsys:

     nnn

   Push 1 on the stack if the value at the top of the stack equals
PVM_NULL. Otherwise push 0.

   Stack: '( VAL -- VAL INT )'


File: poke.info,  Node: Instruction lti,  Next: Instruction ltiu,  Prev: Instruction nnn,  Up: Relational instructions

22.1.11.13 Instruction lti
..........................

Synopsys:

     lti

   Push 1 on the stack if the integer at the under top is less that the
integer at the top.  Otherwise push 0.

   Stack: '( INT INT -- INT INT INT )'


File: poke.info,  Node: Instruction ltiu,  Next: Instruction ltl,  Prev: Instruction lti,  Up: Relational instructions

22.1.11.14 Instruction ltiu
...........................

Synopsys:

     ltiu

   Push 1 on the stack if the unsigned integer at the under top is less
that the unsigned integer at the top.  Otherwise push 0.

   Stack: '( UINT INT -- UINT UINT INT )'


File: poke.info,  Node: Instruction ltl,  Next: Instruction ltlu,  Prev: Instruction ltiu,  Up: Relational instructions

22.1.11.15 Instruction ltl
..........................

Synopsys:

     ltl

   Push 1 on the stack if the long at the under top is less that the
long at the top.  Otherwise push 0.

   Stack: '( LONG LONG -- LONG LONG INT )'


File: poke.info,  Node: Instruction ltlu,  Next: Instruction lei,  Prev: Instruction ltl,  Up: Relational instructions

22.1.11.16 Instruction ltlu
...........................

Synopsys:

     ltlu

   Push 1 on the stack if the unsigned long at the under top is less
that the unsigned long at the top.  Otherwise push 0.

   Stack: '( ULONG ULONG -- ULONG ULONG INT )'


File: poke.info,  Node: Instruction lei,  Next: Instruction leiu,  Prev: Instruction ltlu,  Up: Relational instructions

22.1.11.17 Instruction lei
..........................

Synopsys:

     lei

   Push 1 on the stack if the integer at the under top is less or equal
that the integer at the top.  Otherwise push 0.

   Stack: '( INT INT -- INT INT INT )'


File: poke.info,  Node: Instruction leiu,  Next: Instruction lel,  Prev: Instruction lei,  Up: Relational instructions

22.1.11.18 Instruction leiu
...........................

Synopsys:

     leiu

   Push 1 on the stack if the unsigned integer at the under top is less
or equal that the unsigned integer at the top.  Otherwise push 0.

   Stack: '( UINT UINT -- UINT UINT INT )'


File: poke.info,  Node: Instruction lel,  Next: Instruction lelu,  Prev: Instruction leiu,  Up: Relational instructions

22.1.11.19 Instruction lel
..........................

Synopsys:

     lel

   Push 1 on the stack if the long at the under top is less or equal
that the long at the top.  Otherwise push 0.

   Stack: '( LONG LONG -- LONG LONG INT )'


File: poke.info,  Node: Instruction lelu,  Next: Instruction gti,  Prev: Instruction lel,  Up: Relational instructions

22.1.11.20 Instruction lelu
...........................

Synopsys:

     lelu

   Push 1 on the stack if the unsigned long at the under top is less or
equal that the unsigned long at the top.  Otherwise push 0.

   Stack: '( ULONG ULONG -- ULONG ULONG INT )'


File: poke.info,  Node: Instruction gti,  Next: Instruction gtiu,  Prev: Instruction lelu,  Up: Relational instructions

22.1.11.21 Instruction gti
..........................

Synopsys:

     gti

   Push 1 on the stack if the integer at the under top is greater than
the integer at the top.  Otherwise push 0.

   Stack: '( INT INT -- INT INT INT )'


File: poke.info,  Node: Instruction gtiu,  Next: Instruction gtl,  Prev: Instruction gti,  Up: Relational instructions

22.1.11.22 Instruction gtiu
...........................

Synopsys:

     gtiu

   Push 1 on the stack if the unsigned integer at the under top is
greater than the unsigned integer at the top.  Otherwise push 0.

   Stack: '( UINT UINT -- UINT UINT INT )'


File: poke.info,  Node: Instruction gtl,  Next: Instruction gtlu,  Prev: Instruction gtiu,  Up: Relational instructions

22.1.11.23 Instruction gtl
..........................

Synopsys:

     gtl

   Push 1 on the stack if the long at the under top is greater than the
long at the top.  Otherwise push 0.

   Stack: '( LONG LONG -- LONG LONG INT )'


File: poke.info,  Node: Instruction gtlu,  Next: Instruction gei,  Prev: Instruction gtl,  Up: Relational instructions

22.1.11.24 Instruction gtlu
...........................

Synopsys:

     gtlu

   Push 1 on the stack if the unsigned long at the under top is greater
than the unsigned long at the top.  Otherwise push 0.

   Stack: '( LONG LONG -- LONG LONG INT )'


File: poke.info,  Node: Instruction gei,  Next: Instruction geiu,  Prev: Instruction gtlu,  Up: Relational instructions

22.1.11.25 Instruction gei
..........................

Synopsys:

     gei

   Push 1 on the stack if the integer at the under top is greater or
equal than the integer at the top.  Otherwise push 0.

   Stack: '( INT INT -- INT INT INT )'


File: poke.info,  Node: Instruction geiu,  Next: Instruction gel,  Prev: Instruction gei,  Up: Relational instructions

22.1.11.26 Instruction geiu
...........................

Synopsys:

     geiu

   Push 1 on the stack if the unsigned integer at the under top is
greater or equal than the unsigned integer at the top.  Otherwise push
0.

   Stack: '( UINT UINT -- UINT UINT INT )'


File: poke.info,  Node: Instruction gel,  Next: Instruction gelu,  Prev: Instruction geiu,  Up: Relational instructions

22.1.11.27 Instruction gel
..........................

Synopsys:

     gel

   Push 1 on the stack if the long at the under top is greater or equal
than the long at the top.  Otherwise push 0.

   Stack: '( LONG LONG -- LONG LONG INT )'


File: poke.info,  Node: Instruction gelu,  Next: Instruction lts,  Prev: Instruction gel,  Up: Relational instructions

22.1.11.28 Instruction gelu
...........................

Synopsys:

     gelu

   Push 1 on the stack if the unsigned long at the under top is greater
or equal than the unsigned long at the top.  Otherwise push 0.

   Stack: '( ULONG ULONG -- ULONG ULONG INT )'


File: poke.info,  Node: Instruction lts,  Next: Instruction gts,  Prev: Instruction gelu,  Up: Relational instructions

22.1.11.29 Instruction lts
..........................

Synopsys:

     lts

   Push 1 on the stack if the string at the under top is less than the
string at the top, in lexicographic order.  Otherwise push 0.

   Stack: '( STR STR -- STR STR INT )'


File: poke.info,  Node: Instruction gts,  Next: Instruction ges,  Prev: Instruction lts,  Up: Relational instructions

22.1.11.30 Instruction gts
..........................

Synopsys:

     gts

   Push 1 on the stack if the string at the under top is greater than
the string at the top, in lexicographic order.  Otherwise push 0.

   Stack: '( STR STR -- STR STR INT )'


File: poke.info,  Node: Instruction ges,  Next: Instruction les,  Prev: Instruction gts,  Up: Relational instructions

22.1.11.31 Instruction ges
..........................

Synopsys:

     ges

   Push 1 on the stack if the string at the under top is greater or
equal than the string at the top, in lexicographic order.  Otherwise
push 0.

   Stack: '( STR STR -- STR STR INT )'


File: poke.info,  Node: Instruction les,  Next: Instruction eqc,  Prev: Instruction ges,  Up: Relational instructions

22.1.11.32 Instruction les
..........................

Synopsys:

     les

   Push 1 on the stack if the string at the under top is less or equal
than the string at the top, in lexicographic order.  Otherwise push 0.

   Stack: '( STR STR -- STR STR INT )'


File: poke.info,  Node: Instruction eqc,  Next: Instruction nec,  Prev: Instruction les,  Up: Relational instructions

22.1.11.33 Instruction eqc
..........................

Synopsys:

     eqc

   Push 1 on the stack if the two closures at the top of the stack are
equal.  Otherwise push 0.

   Stack: '( CLS CLS -- CLS CLS INT )'


File: poke.info,  Node: Instruction nec,  Prev: Instruction eqc,  Up: Relational instructions

22.1.11.34 Instruction nec
..........................

Synopsys:

     nec

   Push 1 on the stack if the two closures at the top of the stack are
not equal.  Otherwise push 0.

   Stack: '( CLS CLS -- CLS CLS INT )'


File: poke.info,  Node: Concatenation instructions,  Next: Logical instructions,  Prev: Relational instructions,  Up: PVM Instructions

22.1.12 Concatenation instructions
----------------------------------

* Menu:

* Instruction sconc::


File: poke.info,  Node: Instruction sconc,  Up: Concatenation instructions

22.1.12.1 Instruction sconc
...........................

Synopsys:

     sconc

   Push the concatenation of the two strings at the top of the stack.

   Stack: '( STR STR -- STR STR STR )'


File: poke.info,  Node: Logical instructions,  Next: Bitwise instructions,  Prev: Concatenation instructions,  Up: PVM Instructions

22.1.13 Logical instructions
----------------------------

* Menu:

* Instruction and::
* Instruction or::
* Instruction not::


File: poke.info,  Node: Instruction and,  Next: Instruction or,  Up: Logical instructions

22.1.13.1 Instruction and
.........................

Synopsys:

     and

   Push the logical and of the two elements at the top of the stack.

   Stack: '( INT INT -- INT INT INT )'


File: poke.info,  Node: Instruction or,  Next: Instruction not,  Prev: Instruction and,  Up: Logical instructions

22.1.13.2 Instruction or
........................

Synopsys:

     or

   Push the logical or of the two elements at the top of the stack.

   Stack: '( INT INT -- INT INT INT )'


File: poke.info,  Node: Instruction not,  Prev: Instruction or,  Up: Logical instructions

22.1.13.3 Instruction not
.........................

Synopsys:

     not

   Push the logical not of the element at the top of the stack.

   Stack: '( INT -- INT INT )'


File: poke.info,  Node: Bitwise instructions,  Next: Shift instructions,  Prev: Logical instructions,  Up: PVM Instructions

22.1.14 Bitwise instructions
----------------------------

* Menu:

* Instruction bxori::
* Instruction bxoriu::
* Instruction bxorl::
* Instruction bxorlu::
* Instruction bori::
* Instruction boriu::
* Instruction borl::
* Instruction borlu::
* Instruction bandi::
* Instruction bandiu::
* Instruction bandl::
* Instruction bandlu::
* Instruction bnoti::
* Instruction bnotiu::
* Instruction bnotl::
* Instruction bnotlu::


File: poke.info,  Node: Instruction bxori,  Next: Instruction bxoriu,  Up: Bitwise instructions

22.1.14.1 Instruction bxori
...........................

Synopsys:

     bxori

   Push the bitwise exclusive or of the two integers at the top of the
stack.

   Stack: '( INT INT -- INT INT INT )'


File: poke.info,  Node: Instruction bxoriu,  Next: Instruction bxorl,  Prev: Instruction bxori,  Up: Bitwise instructions

22.1.14.2 Instruction bxoriu
............................

Synopsys:

     bxoriu

   Push the bitwise exclusive or of the two unsigned integers at the top
of the stack.

   Stack: '( UINT UINT -- UINT UINT UINT )'


File: poke.info,  Node: Instruction bxorl,  Next: Instruction bxorlu,  Prev: Instruction bxoriu,  Up: Bitwise instructions

22.1.14.3 Instruction bxorl
...........................

Synopsys:

     bxorl

   Push the bitwise exclusive or of the two longs at the top of the
stack.

   Stack: '( LONG LONG -- LONG LONG LONG )'


File: poke.info,  Node: Instruction bxorlu,  Next: Instruction bori,  Prev: Instruction bxorl,  Up: Bitwise instructions

22.1.14.4 Instruction bxorlu
............................

Synopsys:

     bxorlu

   Push the bitwise exclusive or of the two unsigned longs at the top of
the stack.

   Stack: '( ULONG ULONG -- ULONG ULONG ULONG )'


File: poke.info,  Node: Instruction bori,  Next: Instruction boriu,  Prev: Instruction bxorlu,  Up: Bitwise instructions

22.1.14.5 Instruction bori
..........................

Synopsys:

     bori

   Push the bitwise or of the two integers at the top of the stack.

   Stack: '( INT INT -- INT INT INT )'


File: poke.info,  Node: Instruction boriu,  Next: Instruction borl,  Prev: Instruction bori,  Up: Bitwise instructions

22.1.14.6 Instruction boriu
...........................

Synopsys:

     boriu

   Push the bitwise or of the two unsigned integers at the top of the
stack.

   Stack: '( UINT UINT -- UINT UINT UINT )'


File: poke.info,  Node: Instruction borl,  Next: Instruction borlu,  Prev: Instruction boriu,  Up: Bitwise instructions

22.1.14.7 Instruction borl
..........................

Synopsys:

     borl

   Push the bitwise or of the two longs at the top of the stack.

   Stack: '( LONG LONG -- LONG LONG LONG )'


File: poke.info,  Node: Instruction borlu,  Next: Instruction bandi,  Prev: Instruction borl,  Up: Bitwise instructions

22.1.14.8 Instruction borlu
...........................

Synopsys:

     borlu

   Push the bitwise or of the two longs at the top of the stack.

   Stack: '( ULONG ULONG -- ULONG ULONG ULONG )'


File: poke.info,  Node: Instruction bandi,  Next: Instruction bandiu,  Prev: Instruction borlu,  Up: Bitwise instructions

22.1.14.9 Instruction bandi
...........................

Synopsys:

     bandi

   Push the bitwise and of the two integers at the top of the stack.

   Stack: '( INT INT -- INT INT INT )'


File: poke.info,  Node: Instruction bandiu,  Next: Instruction bandl,  Prev: Instruction bandi,  Up: Bitwise instructions

22.1.14.10 Instruction bandiu
.............................

Synopsys:

     bandiu

   Push the bitwise and of the two unsigned integers at the top of the
stack.

   Stack: '( UINT UINT -- UINT UINT UINT )'


File: poke.info,  Node: Instruction bandl,  Next: Instruction bandlu,  Prev: Instruction bandiu,  Up: Bitwise instructions

22.1.14.11 Instruction bandl
............................

Synopsys:

     bandl

   Push the bitwise and of the two longs at the top of the stack.

   Stack: '( LONG LONG -- LONG LONG LONG )'


File: poke.info,  Node: Instruction bandlu,  Next: Instruction bnoti,  Prev: Instruction bandl,  Up: Bitwise instructions

22.1.14.12 Instruction bandlu
.............................

Synopsys:

     bandlu

   Push the bitwise and of the two unsigned longs at the top of the
stack.

   Stack: '( ULONG ULONG -- ULONG ULONG ULONG )'


File: poke.info,  Node: Instruction bnoti,  Next: Instruction bnotiu,  Prev: Instruction bandlu,  Up: Bitwise instructions

22.1.14.13 Instruction bnoti
............................

Synopsys:

     bnoti

   Push the bitwise not of the integer at the top of the stack.

   Stack: '( INT -- INT INT INT )'


File: poke.info,  Node: Instruction bnotiu,  Next: Instruction bnotl,  Prev: Instruction bnoti,  Up: Bitwise instructions

22.1.14.14 Instruction bnotiu
.............................

Synopsys:

     bnotiu

   Push the bitwise not of the unsigned integer at the top of the stack.

   Stack: '( UINT -- UINT UINT )'


File: poke.info,  Node: Instruction bnotl,  Next: Instruction bnotlu,  Prev: Instruction bnotiu,  Up: Bitwise instructions

22.1.14.15 Instruction bnotl
............................

Synopsys:

     bnotl

   Push the bitwise not of the long at the top of the stack.

   Stack: '( LONG -- LONG LONG )'


File: poke.info,  Node: Instruction bnotlu,  Prev: Instruction bnotl,  Up: Bitwise instructions

22.1.14.16 Instruction bnotlu
.............................

Synopsys:

     bnotlu

   Push the bitwise not of the unsigned long at the top of the stack.

   Stack: '( ULONG -- ULONG ULONG )'


File: poke.info,  Node: Shift instructions,  Next: Compare-and-swap instructions,  Prev: Bitwise instructions,  Up: PVM Instructions

22.1.15 Shift instructions
--------------------------

* Menu:

* Instruction bsli::
* Instruction bsliu::
* Instruction bsll::
* Instruction bsllu::
* Instruction bsri::
* Instruction bsriu::
* Instruction bsrl::
* Instruction bsrlu::


File: poke.info,  Node: Instruction bsli,  Next: Instruction bsliu,  Up: Shift instructions

22.1.15.1 Instruction bsli
..........................

Synopsys:

     bsli

   Left-shift the integer at the under top of the stack the number of
bits indicated by the unsigned int at the top of the stack.

   If the bit count is equal or bigger than the size of the left
operand, then raise PVM_E_OUT_OF_BOUNDS.

   Stack: '( INT UINT -- INT UINT INT )'

   Exceptions: 'PVM_E_OUT_OF_BOUNDS'


File: poke.info,  Node: Instruction bsliu,  Next: Instruction bsll,  Prev: Instruction bsli,  Up: Shift instructions

22.1.15.2 Instruction bsliu
...........................

Synopsys:

     bsliu

   Left-shift the unsigned integer at the under top of the stack the
number of bits indicated by the unsigned int at the top of the stack.

   If the bit count is equal or bigger than the size of the left
operand, then raise PVM_E_OUT_OF_BOUNDS.

   Stack: '( UINT UINT -- UINT UINT UINT )'

   Exceptions: 'PVM_E_OUT_OF_BOUNDS'


File: poke.info,  Node: Instruction bsll,  Next: Instruction bsllu,  Prev: Instruction bsliu,  Up: Shift instructions

22.1.15.3 Instruction bsll
..........................

Synopsys:

     bsll

   Left-shift the long at the under top of the stack the number of bits
indicated by the unsigned int at the top of the stack.

   If the bit count is equal or bigger than the size of the left
operand, then raise PVM_E_OUT_OF_BOUNDS.

   Stack: '( LONG UINT -- LONG UINT LONG )'

   Exceptions: 'PVM_E_OUT_OF_BOUNDS'


File: poke.info,  Node: Instruction bsllu,  Next: Instruction bsri,  Prev: Instruction bsll,  Up: Shift instructions

22.1.15.4 Instruction bsllu
...........................

Synopsys:

     bsllu

   Left-shift the unsigned long at the under top of the stack the number
of bits indicated by the unsigned int at the top of the stack.

   If the bit count is equal or bigger than the size of the left
operand, then raise PVM_E_OUT_OF_BOUNDS.

   Stack: '( ULONG UINT -- ULONG UINT ULONG )'

   Exceptions: 'PVM_E_OUT_OF_BOUNDS'


File: poke.info,  Node: Instruction bsri,  Next: Instruction bsriu,  Prev: Instruction bsllu,  Up: Shift instructions

22.1.15.5 Instruction bsri
..........................

Synopsys:

     bsri

   Right-shift the integer at the under top of the stack the number of
tis indicated by the unsigned int at the top of the stack.

   Stack: '( INT UINT -- INT UINT INT )'


File: poke.info,  Node: Instruction bsriu,  Next: Instruction bsrl,  Prev: Instruction bsri,  Up: Shift instructions

22.1.15.6 Instruction bsriu
...........................

Synopsys:

     bsriu

   Right-shift the unsigned integer at the under top of the stack the
number of tis indicated by the unsigned int at the top of the stack.

   Stack: '( UINT UINT -- UINT UINT UINT )'


File: poke.info,  Node: Instruction bsrl,  Next: Instruction bsrlu,  Prev: Instruction bsriu,  Up: Shift instructions

22.1.15.7 Instruction bsrl
..........................

Synopsys:

     bsrl

   Right-shift the long at the under top of the stack the number of tis
indicated by the unsigned int at the top of the stack.

   Stack: '( LONG UINT -- LONG UINT LONG )'


File: poke.info,  Node: Instruction bsrlu,  Prev: Instruction bsrl,  Up: Shift instructions

22.1.15.8 Instruction bsrlu
...........................

Synopsys:

     bsrlu

   Right-shift the unsigned long at the under top of the stack the
number of tis indicated by the unsigned int at the top of the stack.

   Stack: '( ULONG UINT -- ULONG UINT ULONG )'


File: poke.info,  Node: Compare-and-swap instructions,  Next: Branch instructions,  Prev: Shift instructions,  Up: PVM Instructions

22.1.16 Compare-and-swap instructions
-------------------------------------

* Menu:

* Instruction swapgti::
* Instruction swapgtiu::
* Instruction swapgtl::
* Instruction swapgtlu::


File: poke.info,  Node: Instruction swapgti,  Next: Instruction swapgtiu,  Up: Compare-and-swap instructions

22.1.16.1 Instruction swapgti
.............................

Synopsys:

     swapgti

   Swap the two integers at the top of the stack if the element at the
under-top is greater than the element at the top.

   Stack: '( INT INT -- INT INT )'


File: poke.info,  Node: Instruction swapgtiu,  Next: Instruction swapgtl,  Prev: Instruction swapgti,  Up: Compare-and-swap instructions

22.1.16.2 Instruction swapgtiu
..............................

Synopsys:

     swapgtiu

   Swap the two unsigned integers at the top of the stack if the element
at the under-top is greater than the element at the top.

   Stack: '( UINT UINT -- UINT UINT )'


File: poke.info,  Node: Instruction swapgtl,  Next: Instruction swapgtlu,  Prev: Instruction swapgtiu,  Up: Compare-and-swap instructions

22.1.16.3 Instruction swapgtl
.............................

Synopsys:

     swapgtl

   Swap the two longs at the top of the stack if the element at the
under-top is greater than the element at the top.

   Stack: '( LONG LONG -- LONG LONG )'


File: poke.info,  Node: Instruction swapgtlu,  Prev: Instruction swapgtl,  Up: Compare-and-swap instructions

22.1.16.4 Instruction swapgtlu
..............................

Synopsys:

     swapgtlu

   Swap the two unsigned longs at the top of the stack if the element at
the under-top is greater than the element at the top.

   Stack: '( ULONG ULONG -- ULONG ULONG )'


File: poke.info,  Node: Branch instructions,  Next: Conversion instructions,  Prev: Compare-and-swap instructions,  Up: PVM Instructions

22.1.17 Branch instructions
---------------------------

* Menu:

* Instruction ba::
* Instruction bn::
* Instruction bnn::
* Instruction bzi::
* Instruction bziu::
* Instruction bzl::
* Instruction bzlu::
* Instruction bnzi::
* Instruction bnziu::
* Instruction bnzl::
* Instruction bnzlu::


File: poke.info,  Node: Instruction ba,  Next: Instruction bn,  Up: Branch instructions

22.1.17.1 Instruction ba
........................

Synopsys:

     ba LABEL

   Branch unconditionally to the given LABEL.

   Stack: '( -- )'


File: poke.info,  Node: Instruction bn,  Next: Instruction bnn,  Prev: Instruction ba,  Up: Branch instructions

22.1.17.2 Instruction bn
........................

Synopsys:

     bn LABEL

   Branch to the given LABEL if the value at the top of the stack is
PVM_NULL.

   Stack: '( VAL -- VAL )'


File: poke.info,  Node: Instruction bnn,  Next: Instruction bzi,  Prev: Instruction bn,  Up: Branch instructions

22.1.17.3 Instruction bnn
.........................

Synopsys:

     bnn LABEL

   Branch to the given LABEL if the value at the top of the stack is not
PVM_NULL.

   Stack: '( VAL -- VAL )'


File: poke.info,  Node: Instruction bzi,  Next: Instruction bziu,  Prev: Instruction bnn,  Up: Branch instructions

22.1.17.4 Instruction bzi
.........................

Synopsys:

     bzi LABEL

   Branch to the given LABEL if the integer at the top of the stack is
zero.

   Stack: '( INT -- INT )'


File: poke.info,  Node: Instruction bziu,  Next: Instruction bzl,  Prev: Instruction bzi,  Up: Branch instructions

22.1.17.5 Instruction bziu
..........................

Synopsys:

     bziu LABEL

   Branch to the given LABEL if the unsigned integer at the top of the
stack is zero.

   Stack: '( UINT -- UINT )'


File: poke.info,  Node: Instruction bzl,  Next: Instruction bzlu,  Prev: Instruction bziu,  Up: Branch instructions

22.1.17.6 Instruction bzl
.........................

Synopsys:

     bzl LABEL

   Branch to the given LABEL if the long at the top of the stack is
zero.

   Stack: '( LONG -- LONG )'


File: poke.info,  Node: Instruction bzlu,  Next: Instruction bnzi,  Prev: Instruction bzl,  Up: Branch instructions

22.1.17.7 Instruction bzlu
..........................

Synopsys:

     bzlu LABEL

   Branch to the given LABEL if the unsigned long at the top of the
stack is zero.

   Stack: '( ULONG -- ULONG )'


File: poke.info,  Node: Instruction bnzi,  Next: Instruction bnziu,  Prev: Instruction bzlu,  Up: Branch instructions

22.1.17.8 Instruction bnzi
..........................

Synopsys:

     bnzi LABEL

   Branch to the given LABEL if the integer at the top of the stack is
nonzero.

   Stack: '( INT -- INT )'


File: poke.info,  Node: Instruction bnziu,  Next: Instruction bnzl,  Prev: Instruction bnzi,  Up: Branch instructions

22.1.17.9 Instruction bnziu
...........................

Synopsys:

     bnziu LABEL

   Branch to the given LABEL if the unsigned integer at the top of the
stack is nonzero.

   Stack: '( UINT -- UINT )'


File: poke.info,  Node: Instruction bnzl,  Next: Instruction bnzlu,  Prev: Instruction bnziu,  Up: Branch instructions

22.1.17.10 Instruction bnzl
...........................

Synopsys:

     bnzl LABEL

   Branch to the given LABEL if the long at the top of the stack is
nonzero.

   Stack: '( LONG -- LONG )'


File: poke.info,  Node: Instruction bnzlu,  Prev: Instruction bnzl,  Up: Branch instructions

22.1.17.11 Instruction bnzlu
............................

Synopsys:

     bnzlu LABEL

   Branch to the given LABEL if the unsigned long at the top of the
stack is nonzero.

   Stack: '( ULONG -- ULONG )'


File: poke.info,  Node: Conversion instructions,  Next: String instructions,  Prev: Branch instructions,  Up: PVM Instructions

22.1.18 Conversion instructions
-------------------------------

* Menu:

* Instruction ctos::
* Instruction itoi::
* Instruction itoiu::
* Instruction itol::
* Instruction itolu::
* Instruction iutoi::
* Instruction iutoiu::
* Instruction iutol::
* Instruction iutolu::
* Instruction ltoi::
* Instruction ltoiu::
* Instruction ltol::
* Instruction ltolu::
* Instruction lutoi::
* Instruction lutoiu::
* Instruction lutol::
* Instruction lutolu::


File: poke.info,  Node: Instruction ctos,  Next: Instruction itoi,  Up: Conversion instructions

22.1.18.1 Instruction ctos
..........................

Synopsys:

     ctos

   Convert the character encoded as an unsigned integer at the top of
the stack to a string that contains just that character.

   Stack: '( UINT -- UINT STR )'


File: poke.info,  Node: Instruction itoi,  Next: Instruction itoiu,  Prev: Instruction ctos,  Up: Conversion instructions

22.1.18.2 Instruction itoi
..........................

Synopsys:

     itoi NBITS

   Convert the integer at the top of the stack to an integer featuring
NBITS bits.

   NBITS can be any number from 1 to 32.

   Stack: '( INT -- INT INT )'


File: poke.info,  Node: Instruction itoiu,  Next: Instruction itol,  Prev: Instruction itoi,  Up: Conversion instructions

22.1.18.3 Instruction itoiu
...........................

Synopsys:

     itoiu NBITS

   Convert the integer at the top of the stack to an unsigned integer
featuring NBITS bits.

   NBITS can be any number from 1 to 32.

   Stack: '( INT -- INT UINT )'


File: poke.info,  Node: Instruction itol,  Next: Instruction itolu,  Prev: Instruction itoiu,  Up: Conversion instructions

22.1.18.4 Instruction itol
..........................

Synopsys:

     itol NBITS

   Convert the integer at the top of the stack to a long featuring NBITS
bits.

   NBITS can be any number from 1 to 64.

   Stack: '( INT -- INT LONG )'


File: poke.info,  Node: Instruction itolu,  Next: Instruction iutoi,  Prev: Instruction itol,  Up: Conversion instructions

22.1.18.5 Instruction itolu
...........................

Synopsys:

     itolu NBITS

   Convert the integer at the top of the stack to an unsigned long
featuring NBITS bits.

   NBITS can be any number from 1 to 64.

   Stack: '( INT -- INT ULONG )'


File: poke.info,  Node: Instruction iutoi,  Next: Instruction iutoiu,  Prev: Instruction itolu,  Up: Conversion instructions

22.1.18.6 Instruction iutoi
...........................

Synopsys:

     iutoi NBITS

   Convert the unsigned integer at the top of the stack to an integer
featuring NBITS bits.

   NBITS can be any number from 1 to 32.

   Stack: '( UINT -- UINT INT )'


File: poke.info,  Node: Instruction iutoiu,  Next: Instruction iutol,  Prev: Instruction iutoi,  Up: Conversion instructions

22.1.18.7 Instruction iutoiu
............................

Synopsys:

     iutoiu NBITS

   Convert the unsigned integer at the top of the stack to an unsigned
integer featuring NBITS bits.

   NBITS can be any number from 1 to 32.

   Stack: '( UINT -- UINT UINT )'


File: poke.info,  Node: Instruction iutol,  Next: Instruction iutolu,  Prev: Instruction iutoiu,  Up: Conversion instructions

22.1.18.8 Instruction iutol
...........................

Synopsys:

     iutol NBITS

   Convert the unsigned integer at the top of the stack to a long
featuring NBITS bits.

   NBITS can be any number from 1 to 64.

   Stack: '( UINT -- UINT LONG )'


File: poke.info,  Node: Instruction iutolu,  Next: Instruction ltoi,  Prev: Instruction iutol,  Up: Conversion instructions

22.1.18.9 Instruction iutolu
............................

Synopsys:

     iutolu NBITS

   Convert the unsigned integer at the top of the stack to an unsigned
long featuring NBITS bits.

   NBITS can be any number from 1 to 64.

   Stack: '( UINT -- UINT ULONG )'


File: poke.info,  Node: Instruction ltoi,  Next: Instruction ltoiu,  Prev: Instruction iutolu,  Up: Conversion instructions

22.1.18.10 Instruction ltoi
...........................

Synopsys:

     ltoi NBITS

   Convert the long at the top of the stack to an integer featuring
NBITS bits.

   NBITS can be any number from 1 to 32.

   Stack: '( LONG -- LONG INT )'


File: poke.info,  Node: Instruction ltoiu,  Next: Instruction ltol,  Prev: Instruction ltoi,  Up: Conversion instructions

22.1.18.11 Instruction ltoiu
............................

Synopsys:

     ltoiu NBITS

   Convert the long at the top of the stack to an unsigned integer
featuring NBITS bits.

   NBITS can be any number from 1 to 32.

   Stack: '( LONG -- LONG UINT )'


File: poke.info,  Node: Instruction ltol,  Next: Instruction ltolu,  Prev: Instruction ltoiu,  Up: Conversion instructions

22.1.18.12 Instruction ltol
...........................

Synopsys:

     ltol NBITS

   Convert the long at the top of the stack to a long featuring NBITS
bits.

   NBITS can be any number from 1 to 64.

   Stack: '( LONG -- LONG LONG )'


File: poke.info,  Node: Instruction ltolu,  Next: Instruction lutoi,  Prev: Instruction ltol,  Up: Conversion instructions

22.1.18.13 Instruction ltolu
............................

Synopsys:

     ltolu NBITS

   Convert the long at the top of the stack to an unsigned long
featuring NBITS bits.

   NBITS can be any number from 1 to 64.

   Stack: '( LONG -- LONG ULONG )'


File: poke.info,  Node: Instruction lutoi,  Next: Instruction lutoiu,  Prev: Instruction ltolu,  Up: Conversion instructions

22.1.18.14 Instruction lutoi
............................

Synopsys:

     lutoi NBITS

   Convert the unsigned long at the top of the stack to an integer
featuring NBITS bits.

   NBITS can be any number from 1 to 32.

   Stack: '( ULONG -- ULONG INT )'


File: poke.info,  Node: Instruction lutoiu,  Next: Instruction lutol,  Prev: Instruction lutoi,  Up: Conversion instructions

22.1.18.15 Instruction lutoiu
.............................

Synopsys:

     lutoiu NBITS

   Convert the unsigned long at the top of the stack to an unsigned
integer featuring NBITS bits.

   NBITS can be any number from 1 to 32.

   Stack: '( ULONG -- ULONG UINT )'


File: poke.info,  Node: Instruction lutol,  Next: Instruction lutolu,  Prev: Instruction lutoiu,  Up: Conversion instructions

22.1.18.16 Instruction lutol
............................

Synopsys:

     lutol NBITS

   Convert the unsigned long at the top of the stack to a long featuring
NBITS bits.

   Stack: '( ULONG -- ULONG LONG )'


File: poke.info,  Node: Instruction lutolu,  Prev: Instruction lutol,  Up: Conversion instructions

22.1.18.17 Instruction lutolu
.............................

Synopsys:

     lutolu NBITS

   Convert the unsigned long at the top of the stack to an unsigned long
featuring NBITS bits.

   Stack: '( ULONG -- ULONG ULONG )'


File: poke.info,  Node: String instructions,  Next: Array instructions,  Prev: Conversion instructions,  Up: PVM Instructions

22.1.19 String instructions
---------------------------

* Menu:

* Instruction strref::
* Instruction strset::
* Instruction substr::
* Instruction muls::
* Instruction sprops::
* Instruction sproph::
* Instruction spropc::


File: poke.info,  Node: Instruction strref,  Next: Instruction strset,  Up: String instructions

22.1.19.1 Instruction strref
............................

Synopsys:

     strref

   Given a string and an unsigned long at the top of the stack, push an
unsigned integer with the code of the character that occupies that
position in the string, on the stack.

   The index is zero-based.  If it is less than 0 or exceeds the length
of the string, then PVM_E_OUT_OF_BOUNDS is raised.

   Stack: '( STR ULONG -- STR ULONG UINT )'

   Exceptions: 'PVM_E_OUT_OF_BOUNDS'


File: poke.info,  Node: Instruction strset,  Next: Instruction substr,  Prev: Instruction strref,  Up: String instructions

22.1.19.2 Instruction strset
............................

Synopsys:

     strset

   Given a string STR, an index FROM and a string NEWSTR, copy the
content of NEWSTR to STR at index FROM.

   Index is zero-based.

   If FROM >= the size of the string, or if FROM+len(NEWSTR) > the size
of the string, raise the PVM_E_OUT_OF_BOUNDS exception.

   Stack: '( STR ULONG NEWSTR -- STR )'

   Exceptions: 'PVM_E_OUT_OF_BOUNDS'


File: poke.info,  Node: Instruction substr,  Next: Instruction muls,  Prev: Instruction strset,  Up: String instructions

22.1.19.3 Instruction substr
............................

Synopsys:

     substr

   Given a string and two indices FROM and TO conforming a semi-open
interval [FROM,TO), push the substring enclosed by that interval.

   Both indexes are zero-based.

   If FROM >= the size of the string, or if TO > the size of the string,
or if FROM >= TO, raise the PVM_E_OUT_OF_BOUNDS exception.

   Stack: '( STR ULONG(from) ULONG(to) -- STR ULONG(from) ULONG(to) STR
)'

   Exceptions: 'PVM_E_OUT_OF_BOUNDS'


File: poke.info,  Node: Instruction muls,  Next: Instruction sprops,  Prev: Instruction substr,  Up: String instructions

22.1.19.4 Instruction muls
..........................

Synopsys:

     muls

   Given a string and an unsigned long on the stack, push a new string
value whose value is the concatenation of the argument string applied to
itself as many times as the unsigned long.  If the second argument to
muls is 0 then the result of the operation is the empty string.

   Stack: '( STR ULONG -- STR ULONG STR )'


File: poke.info,  Node: Instruction sprops,  Next: Instruction sproph,  Prev: Instruction muls,  Up: String instructions

22.1.19.5 Instruction sprops
............................

Synopsys:

     sprops

   Given a string STR, set the styling class of the substring with
length LEN from index IDX to CLASS.

   Stack: '( STR IDX LEN CLASS -- STR )'


File: poke.info,  Node: Instruction sproph,  Next: Instruction spropc,  Prev: Instruction sprops,  Up: String instructions

22.1.19.6 Instruction sproph
............................

Synopsys:

     sproph

   Given a string STR, set the hyperlink property (which characterized
by a URL and an ID) of the substring with length LEN from index IDX.

   Stack: '( STR IDX LEN URL ID -- STR )'


File: poke.info,  Node: Instruction spropc,  Prev: Instruction sproph,  Up: String instructions

22.1.19.7 Instruction spropc
............................

Synopsys:

     spropc

   Given a string on the stack, push the copy of the string with all
properties cleared.

   Stack: '( STR -- STR )'


File: poke.info,  Node: Array instructions,  Next: Struct instructions,  Prev: String instructions,  Up: PVM Instructions

22.1.20 Array instructions
--------------------------

* Menu:

* Instruction mka::
* Instruction ains::
* Instruction arem::
* Instruction aset::
* Instruction aref::
* Instruction arefo::
* Instruction asettb::


File: poke.info,  Node: Instruction mka,  Next: Instruction ains,  Up: Array instructions

22.1.20.1 Instruction mka
.........................

Synopsys:

     mka

   Make a new empty array value.

   TYP is the type of the new array.

   NELEM is a hint on how many elements to use to initialize the array
value.  This is to avoid allocating memory that will never be used.  Use
0UL when the number of elements in the array are not known in advance;
this will make the PVM to choose a reasonable default.

   Stack: '( TYP ULONG(nelem) -- ARR )'


File: poke.info,  Node: Instruction ains,  Next: Instruction arem,  Prev: Instruction mka,  Up: Array instructions

22.1.20.2 Instruction ains
..........................

Synopsys:

     ains

   Insert a new element VAL, at the end of the array ARR, making it
grow.

   If IDX is less than the current size of the array, the value is
stored in the referred argument.

   If IDX is equal or bigger than the current size of the array, the
same element is replicated in the previous elements.

   Examples:

   a = [a1, a2, a3]

   [a1, a2, a3] 2 VAL ains -> INVAL exception [a1, a2, a3] 3 VAL ains ->
[a1, a2, a3, VAL] [a1, a2, a3] 5 VAL ains -> [a1, a2, a3, VAL, VAL, VAL]

   Stack: '( ARR IDX VAL -- ARR )'

   Exceptions: 'PVM_E_INVAL'


File: poke.info,  Node: Instruction arem,  Next: Instruction aset,  Prev: Instruction ains,  Up: Array instructions

22.1.20.3 Instruction arem
..........................

Synopsys:

     arem

   Remove an element from an array at the specified index, making it
schrink.

   If IDX doesn't correspond to an element in the array, raise
PVM_E_OUT_OF_BOUNDS. This always happens if the array is empty.

   Stack: '( ARR IDX -- ARR )' Exception: PVM_E_OUT_OF_BOUNDS


File: poke.info,  Node: Instruction aset,  Next: Instruction aref,  Prev: Instruction arem,  Up: Array instructions

22.1.20.4 Instruction aset
..........................

Synopsys:

     aset

   Set the value with index ULONG in the array ARR to have the value
VAL. The index in ULONG should be in range, since this instruction is
not checked.

   Stack: '( ARR ULONG VAL -- ARR )'


File: poke.info,  Node: Instruction aref,  Next: Instruction arefo,  Prev: Instruction aset,  Up: Array instructions

22.1.20.5 Instruction aref
..........................

Synopsys:

     aref

   Given an array ARR and an index ULONG, push the element of the array
occupying that position on the stack.

   If the provided index is out of bounds, then raise
PVM_E_OUT_OF_BOUNDS.

   Stack: '( ARR ULONG -- ARR ULONG VAL )'

   Exceptions: 'PVM_E_OUT_OF_BOUNDS'


File: poke.info,  Node: Instruction arefo,  Next: Instruction asettb,  Prev: Instruction aref,  Up: Array instructions

22.1.20.6 Instruction arefo
...........................

Synopsys:

     arefo

   Given an array ARR and an index ULONG, push the offset of the element
occupying that position in the array.

   If the provided index is out of bounds, then raise
PVM_E_OUT_OF_BOUNDS.

   Stack: '( ARR ULONG -- ARR ULONG OFF )'

   Exceptions: 'PVM_E_OUT_OF_BOUNDS'


File: poke.info,  Node: Instruction asettb,  Prev: Instruction arefo,  Up: Array instructions

22.1.20.7 Instruction asettb
............................

Synopsys:

     asettb

   Given an array ARR and a closure BOUND, set the later as the array's
bounder function.  This is a function that, once executed with no
arguments, returns the size of the array.

   Stack: '( ARR BOUND -- ARR )'


File: poke.info,  Node: Struct instructions,  Next: Offset Instructions,  Prev: Array instructions,  Up: PVM Instructions

22.1.21 Struct instructions
---------------------------

* Menu:

* Instruction mksct::
* Instruction sset::
* Instruction sseti::
* Instruction sref::
* Instruction srefo::
* Instruction srefmnt::
* Instruction srefnt::
* Instruction srefi::
* Instruction srefia::
* Instruction srefio::
* Instruction srefin::
* Instruction smodi::

