Pascal-like Input -- library(readconstant)

library(readconst) provides a set of Pascal-like input commands. The commands are

The idea is that these commands consume some number of "tokens" from the input stream (for read_constant/1, skip_constant/0, read_constants/1, and skip_constants/1 this is the current input stream; for read_constant/2, skip_constant/1, read_constants/2, and skip_constants/2 it is the Stream argument; for prompted_constant/2 and prompted_constants/2 it is the user_input stream). prompted_constant/1 and prompted_constants/2 resemble Pascal's readln command; the others resemble Pascal's read command.

These commands skip initial layout (spaces and control characters). There are two kinds of tokens: quoted tokens and unquoted tokens.

A quoted token starts with a single quote (') or a double quote ("). It ends with the same character that it starts with. To include a quote in such a token, write the quote twice. This is the same as Prolog with the character_escapes flag off. (There is currently no way of making read_constant/1 use C-style character escapes.) A token that starts with a single quote will be returned as a Prolog atom, even if it looks like a number. Again, this is the same as Prolog. For example, 5 will be returned as the atom 5, not the integer 5. A token that starts with a double quote will be returned as a list of character codes. For example, """" (four double quotes) will be returned as the list [34]. Both '' (two single quotes) and "" (two double quotes) are acceptable tokens, meaning the atom with no characters in its name ('') and the empty list ([]) respectively.

The character following the closing quote of a quoted token is always discarded. This character is normally a space, tab, newline, or comma.

An unquoted token is anything else. Characters are read until a layout character or a comma is found. The comma or layout character that terminates the token is discarded. The other characters are given to the built-in predicate name/2, so the token will be returned as a number if it looks like a number; otherwise it will be returned as an atom. The syntax of numbers is perforce identical to the syntax of numbers in Quintus Prolog.

In both cases, we have leading layout, which is skipped, the token proper, and a terminating character, which is discarded. If, for example, the input looks like

     fred, 1.2 ' ', last<LFD>
     

and we call read_constants([A,B,C,D]), the bindings will be A=fred, B=1.2, C=' ', D=last, and the entire line will have been consumed. But if the input looks like

     fred, 1.2 ' ', last<SPC><SPC><LFD>
     

the last <SPC> and <LFD> will be left in the input stream.

The input stream can contain end-of-line comments, which begin with a percent sign (%) just as they do in Prolog. A comment will terminate an unquoted token, and will be skipped. Suppose you want a data file that contains a number and a filename. The file could look like this:

     % This is the data file.
     137 % is the number
     foobaz/other-file % is the filename
     

You could read it by calling

     | ?- see('the-file'), read_constants([Nbr,File]), seen.
     

The following predicates are defined in library(readconst):


read_constant(-Constant)
reads a single constant from the current input stream, then unifies Constant with the result.
read_constant(+Stream, -Constant)
reads a single constant from Stream, then unifies Constant with the result.
read_constants(-[X1,...,XN])
The argument must be a proper list. N constants are read from the current input stream, then [X1,...,XN] is unified with a list of the results.
read_constants(+Stream, -[X1,...,XN])
The second argument must be a proper list. N constants are read from Stream, then [X1,...,XN] is unified with a list of the results.
skip_constant
reads a single constant from the current input stream, then throws it away. This produces the same effect as calling read_constant(_), but is more efficient, as it doesn't convert the constant from character form to Prolog form before discarding it.
skip_constant(+Stream)
reads a single constant from Stream and discards it. This produces the same effect as calling read_constant(Stream, _) but is more efficient.
skip_constants(+N)
reads N constants from the current input stream and discards them. N must be a non-negative integer.
skip_constants(+Stream, +N)
reads N constants from Stream and discards them. N must be a non-negative integer.
prompted_constant(+Prompt, -Constant)
writes Prompt to the terminal (to user_output) and reads one constant from it (from user_input) in response, then unifies Constant with the result. This command will flush the rest of the input line after it has read Constant, just like the commands in library(ask). Here is an example:
          | ?- prompted_constant('Guess the magic number: ', X),
          |    integer(X).
          Guess the magic number: 27 is my guess
          
          X = 27
          

The words is my guess and the new-line are discarded.

prompted_constants(+Prompt, -[X1,...,XN])
writes a prompt to the terminal (to user_output) and reads N constants from it (from user_input) in response, then unifies [X1,...,XN] with a list of the results. This command will flush the rest of the input line after it has read [X1,...,XN], just like the commands in library(ask).