On execution, 24FB SCANNING quickly leads to 26DF S NEGATE. This converts the key code B0 first to 01, then to DD, then to 5D, and adds the priority 10h/16d. Code and priority 105D are now pushed on to the machine stack (270D S PUSH PO) while the string following VAL is evaluated. When the code is taken off the stack (2734 S LOOP), it is converted (2773 S TIGHTER) from 5D to 1D, the calculator offset for 35DE val. VAL is a rather sophisticated function, which many Spectrum programmers will never use in their lives. Two examplesof its use: a) in a program to plot curves: the function to be plotted is input as a string s$, eg "SIN X": VAL s$ is evaluatedfor a range of values X and the curve drawn, with s$ used as a label. b) a string can be used as a compact number array: d$ = "312831303130313130313031", the numbers of days in each of the 12 months, takes up much less space in memory than d(12) with the elements 31, 28, etc. VAL d$(2*m-1 TO 2*m) is then the same as d(m). val subroutine 35DE Called from 0028 FP CALC; the executive routine of the VAL X$ and VAL$ X$ functions. Not otherwise called from ROM, andunlikely to be useful in m/c programs. Takes the string X$ and evaluates it as an expression; returns the value, as a number for VAL X$ and as a string for VAL$ X$. Input parameters: the string parameters of X$ on the calculator stack - HL and DE pointing to its first byte and to the stack end respectively - B holds the literal, 1Dh for VAL and 18h for VAL$. Action: save the current BASIC pointer in 5C5D CH ADD - add E3h to the literal; this sets carry for VAL but not for VAL$ - make a "$" flag by SBC A; FFh for VAL or 00 for VAL$ - call 2BF1 STK FETCH to get the string parameters of X$off the calculator stack - call 0030 BC SPACES to make a space of one more than the string length in the work space - make a pointer to the start of X$ - save the pointer to the start of the work space in 5C5D CH ADD - copy X$ into the work space, with an extra byte at theend - put a newline in this extra byte - call 24FB SCANNING with the flag for syntax checking; it will report an error if X$ doesn't evaluate as an expression - check that the character reached by syntax checking isthe newline - if not jump on to V RPORT C to report "Nonsense in BASIC" - XOR FLAGS with the $ flag - AND the result with 01000000b/40h; SCANNING will leavebit 6 of FLAGS zero for a numeric result, one for a string result, and this must match the $ flag. If it does, XOR producesa zero bit 6 and the AND produces a zero byte. _360C_V_RPORT_C: report "Nonsense in BASIC" on any non- zero result - point 5C5D CH ADD to the start of X$ again - call 24FB SCANNING with the flag set for run time; it evaluates X$ as an expression and puts the result on the calculator stack - recover the old value of 5C5D CH ADD and restore it. Exit: into 35BF STK PNTRS, which sets HL and DE to the first byte of the last value and to the stack end respectively. Output parameters: none - the numeric or string value obtained by evaluating theexpression in X$ is now on the calculator stack. VAL FET 1 subroutine 1C56 The executive routines for LET, READ and INPUT don't call 24FB SCANNING directly to evaluate the expression offered; this subroutine is called instead to make sure the string/ numeric status of the result matches what is required, eg to reject LET number = "string". There are two entry points, VAL FET 1 for inputs in the editing area and VAL FET 2 for inputs in the work space: becausethe "status required" flag is in FLAGS for editing area inputs and in FLAGX for work space inputs, in bit 6 in either case. Input parameters: none. Action: read FLAGS. _1C59_VAL_FET_2 (entry here with FLAGX already read): - stack the flag byte; it shows the "status required" - call 24FB SCANNING to evaluate the expression - XOR the result flag now in FLAGS with the "status required" flag from the stack; this zeroes bit 6 if the bit 6s match - AND the result with 01000000b/40h, which zeroes the whole byte if the bit 6s match - if there is a mismatch report "Nonsense in BASIC". Exit: RET for syntax checking - into 2AFF LET in run time, to put the value from the calculator stack in the variable it is assigned to. Output parameters: none - the evaluation result is on the calculator stack. Called from: 1C4E CLASS 02 1E0A READ 1 VAL FET 2 subroutine 1C59 See VAL FET 1 above. Called from: 21B9 IN ASSIGN VALID 371C (3713 ln) Jumps from: 3713 ln valid expression see 24FB SCANNING valid keystroke see 031E K TEST value of BASIC variable see variables VALUE of FOR ... NEXT loop see FOR ... NEXT loops VAL$ key (AE) see also commands, functions and operators, KEYBOARD SCANNING, 0246 extended mode table (c) The J key in E mode with either shift produces the function VAL$; it requires one string operand X$, which must be a string expression enclosed in an extra pair of quotes, such as VAL$ """hello"" + CHR$ 32 + ""there""" or VAL$ """Result = "" + STR$ SIN X". The value of the function is the value of the string expression, eg in these cases "hello there" and "Result = 0.7183402" or whatever. On execution, 24FB SCANNING quickly leads to 26DF S NEGATE. This puts the priority and code 1018 on the machine stack (270D S PUSH PO) while the expression following VAL$ is evaluated. When the code is taken off the stack (274C S STK LST), it is used as the calculator offset for 35DE val$, the same as 35DE val, see above. The function VAL$ is even more recondite than the function VAL: I don't think I personally have ever used it, or seen in used, in a BASIC program. One could envisage a rather fancy program handling functions, in which all functions are input as strings and eg a function h(x) might be constructed by concatenating f(x) and g(x): h$ = VAL$ "f$ + ""* SIN "" + g$" These are deep waters, Watson. VAR A 1 1C22 (28B2 LOOK VARS) Exit from: 1C1F CLASS 01 1C6C CLASS 04 VAR A 2 1C30 (28B2 LOOK VARS) Exit from: 1C22 VAR A 1 (28B2 LOOK VARS) VAR A 3 1C46 (28B2 LOOK VARS) Jumps from: 1C22 VAR A 1 1C30 VAR A 2 variable in assignment see variables, LET key VARIABLE IN ASSIGNMENT SUBROUTINE see 28B2 LOOK VARS variables (BASIC) see also 28B2 LOOK VARS, variables (DEF FN) When the scanning of BASIC expressions encounters a letter of the alphabet, not enclosed in quotation marks, at the start of a new sub-expression, it is read by 26C9 S LETTER as the first byte of a_variable_name. A variable name must begin with a letter, and in the BASIC program area the letter is represented by its normal character code. If this is followed by "(" (28B2 LOOK VARS) the variable is a_numeric_array; if by "$(", a_string_array; if by "$" without "(", a simple_string_variable; otherwise it is a _numeric_variable. If the letter is followed by another alphanumeric character it is a_long_name; otherwise it is a _short_name, which can also be a loop control variable like X inFOR X = Y TO Z. Variables which aren't arrays are often called _simple_variables. A variable is an expression to which a_value can be _assigned, by LET, INPUT or READ, or in the case of arrays, alsoby DIM and LOAD ... DATA; when the assignment is made, the name of the variable together with the value assigned to it is retained in the variables area. Whenever that name is encountered in executing the BASIC, the variable name is found by 28B2 LOOK VARS and following, and its assigned value used in evaluating the expression containing the variable. If no value has been assigned yet, the name won't be found in the variables area, and the executive routine prints the message "Variable notfound". The value of the variable may be a number or a string, or an array of numbers or strings; but arrays, see separate entry in this index, differ from simple variables in that valuescannot be assigned to them till they have been established in the variables area by a DIM statement. The values in the variables area are always either actual numbers in FP form or actual character codes, never string parameters or any cross- reference to other variables etc. In the variables area the "$" and "(" aren't reproduced;the initial_variable_letter is reproduced, always in lower case,but with its first three bits carrying various flags to show what_type of variable it is. You will find a clear exposition ofthis on pages 166-168 of the old Spectrum handbook, pages 144- 146 of the PLus 2 handbook. Summarizing: +-----+---------------+---------------------------------- |1st 3|Type |Initial letter followed by |bits | | +=====+===============+================================== |010 |simple string |length (2 bytes), string text +-----+---------------+---------------------------------- |011 |simple numeric,|5-byte FP number | |1-letter name | +-----+---------------+---------------------------------- |100 |numeric array |length (excluding name and 2-byte | | |length), no of dimensions (1 | | |byte); size (2 bytes) of each; | | |elements (5 bytes each) +-----+---------------+---------------------------------- |101 |simple numeric,|other characters of name, last | |long name |with bit 7 set; 5-byte FP number +-----+---------------+---------------------------------- |110 |string array |length, no of dimensions (1 byte); | | |size (2 bytes) of each dimension; | | |elements (1 byte each) +-----+---------------+---------------------------------- |111 |loop control |VALUE, LIMIT, STEP (5 bytes each; | | |line no (2 bytes) and statement | | |no (1 byte) of looping line +-----+---------------+---------------------------------- Only arrays and string variables contain a record of their_length, in the two bytes after the variable letter; it is the length exclusive of the first three bytes. Loop control variables are always 12h/18d bytes, other numeric variables 5 bytes, plus any letters of the name after the first, the last being marked with bit 7 set. These figures are exclusive of the initial variable letter. String arrays are essentially arrays of single letters. In some respects, eg for slicing purposes, simple strings are handled like one-dimension arrays; but one-dimension arrays havea fixed length, simple strings (zero-dimension arrays?) don't. Another way of looking at this is to say that string arrays, including one-dimensional string arrays, are arrays of strings of fixed length, but simple strings have a length that can be changed; the last dimension of a string array element represents a slicing subscript, and slicing subscripts can also be used with simple strings. Both descriptions are equally valid, and it is a matter of convenience which one is used in any particular context. Only simple numeric variables which aren't loop control variables may have a long name; in long names, spaces and the upper/lower case distinction are ignored: LET long name = PI: PRINT LONGNAME will print 3.14159... An oddity is that colour controls may be included in long variable names: LET followed by E-mode 6 and then typing "yo", without the quotes, will display the variable name "yo" onyellow PAPER in the BASIC listing; better to follow with E-mode 7, or everything else goes yellow as well. Like spaces, this is ignored in matching variable names: you can colour-code your BASIC to your heart's content without confusing the execution, provided you confine the colour codes to the beginning and end of the variable name; see the minor error described under 28B2 LOOK VARS. A_new_variable is one to which no value has been assigned yet. A_declared_variable or_old_variable is one which is already in the variables area with a value; but if a new value is assigned the old value gets overwritten, or in the case of a simple string, the old value is deleted after the new one has been written. The_destination_address is the address in the variables area to which the new variable or the new value has to be written. A_variable_in_assignment is the one mentioned on the left side of a LET or FOR statement, or in a READ or INPUT statement, to be given a value from the right side or from a DATA statement or the keyboard input. If this is also a variableit is called a_source_variable. _FOR_..._NEXT_control_variables, as can be seen from the summary above, are a special category, not handled by 26C9 S LETTER like the other variable names but by the 1D93 FOR and 1DAB NEXT subroutines; see the index entries. The_variables_area is the part of RAM just above the BASIC program area, and is saved with the program by a SAVE command; its start address is kept in 5C4B VARS, and it extends up to the editing area starting at the address kept in 5C59 E LINE. It always ends with an 80-byte, which is used to signal the end of the area, eg at 2900 V EACH in 28B2 LOOK VARS. On start-up or NEW (1219 RAM SET) or CLEAR (1EB7 CLEAR 1) it is reduced to the 80-byte alone, but every time a value is given toa new variable or an array is declared by DIM, the new variable is inserted before the 80-byte, with everything from 5C59 E LINEupwards being moved up. Introduction wide range of types can be handled 0652 SA DATA array found in vbles area 0670 REPORT 2 "Vble not found" 0672 SA V OLD finds length in vbles area 073A SA TYPE 0 header stores program length and program + vbles length 0808 LD CONTRL loads program and vbles 0819 LD CONT 1 checks length of program + vbles 082E LD DATA clears old array from vbles area 084C LD DATA 1 new array put at 80-byte 0873 LD PROG old program and vbles reclaimed, new loaded 08B6 ME CONTRL new vbles must be merged with old 08F0 ME VAR LP new vbles put in at end, or overwrite old 08F9 ME OLD VP checks each old against each new vble 0901 ME OLD V1 searches old vble names for match 0909 ME OLD V2 long names matched in each character 0912 ME OLD V3 loop to check long names 0921 ME VAR L1 replace old vble 0923 ME VAR L2 add new vble