; ; value.s ; ; Table drive expression evaluator for TermScript ; ; © 1995 Straylight ; ;----- Standard Header ------------------------------------------------------ GET libs:header GET libs:swis GET libs:stream ;----- External dependencies ------------------------------------------------ ;----- Main code ------------------------------------------------------------ AREA |Termscript$$Code|,CODE,READONLY ; --- val_readExp --- ; ; On entry: R7, R8, R9 == lookahead token ; R10 == pointer into tokenised buffer ; R11 == evaluation stack pointer ; R12 == anchor pointer ; ; On exit: R7, R8, R9 == lookahead token ; R0, R1 == result of expression ; R10 == moved on to first char after expression ; ; Use: Reads an expression for the current point in the tokenised ; file, and returns it's result. The implementation is ; table driven and should be very fast. EXPORT val_readExp val_readExp ROUT 10val_readExp BL val__operand BLCS val__operator BCS val_readExp ; --- Now work out the result --- BL val__copyRest ;Copy rest of tokens over LTORG ; --- val__operand --- ; ; On entry: R7, R8, R9 == lookahead token ; R10 == pointer into tokenised buffer ; R11 == evaluation stack pointer ; R12 == anchor pointer ; ; On exit: R0 corrupted ; R7, R8, R9 == lookahead token ; R10 modified appropriately ; CS if operand found, ; CC otherwise ; ; Use: Reads an operand from the input, and does appropriate ; stack like things with it. val__operand ROUT STMFD R13!,{R14} ;Stack registers 00val__operand CMP R9,#'&' ;Start a hex number? BEQ %10val__operand ;Yes -- jump ahead CMP R9,#'%' ;Start of a binary number? BEQ %20val__operand ;Yes -- jump ahead CMP R9,#'!' ;An indirection operand? CMPNE R9,#'?' CMPNE R9,#'$' BEQ %40val__operand ;Yes -- jump ahead CMP R9,#'+' ;Unary operator then? CMPNE R9,#'-' BEQ %50val__operand ;Yes -- jump ahead CMPNE R9,#'(' ;A nice bracket? BEQ %60val__operand ;Yes -- jump ahead SUB R14,R9,#'0' ;Set up for a range check CMP R14,#10 ;Is it a digit? MOVCC R0,#0 ;Yes -- set up accumulator BCC %30val__operand ;Yes -- deal with that B %70val__operand ;Assume it's an identifier ; --- Read a hex number --- 10val__operand BL getToken ;Get another token MOV R0,#0 ;The number so far SUB R14,R9,#'A' ;Check if it's a letter CMP R14,#6 ;But only A-F ADDCC R14,R14,#10 ;If so, add 10 on SUBCS R14,R9,#'0' ;Otherwise check for digit CMPCS R14,#10 ;Make sure it's OK BCC %12val__operand ;And jump head MOV R0,#err_badHex ;Point to error message B error_report ;And return the error 11val__operand SUB R14,R9,#'A' ;Check if it's a letter CMP R14,#6 ;But only A-F ADDCC R14,R14,#10 ;If so, add 10 on SUBCS R14,R9,#'0' ;Otherwise check for digit CMPCS R14,#10 ;Make sure it's OK BCS %35val__readSimple ;No -- that's it then 12val__operand ADD R0,R14,R0,LSL #4 ;Multiply by 16 and add digit BL getToken ;Load a character B %11val__readSimple ;Keep on reading more ; --- Read a binary number --- 20val__operand BL getToken ;Get another token MOV R0,#0 ;The number so far SUB R14,R9,#'0' ;Set up for a range check CMP R14,#1 ;Is it a digit BLS %22val__readSimple ;Yes -- jump ahead MOV R0,#err_badBinary ;Point to error message B error_report ;And return the error 21val__operand SUB R14,R9,#'0' ;Set up for a range check CMP R14,#1 ;Is it a digit BHI %35val__readSimple ;Nope -- jump ahead then 22val__operand ADC R0,R0,R0 ;Multiply by 2 BL getToken ;Load a character B %21val__readSimple ;Keep on reading more ; --- Read a decimal number --- 30val__operand SUB R14,R9,#'0' ;Set up for a range check CMP R14,#10 ;Is it a digit BCS %35val__readSimple ;Nope -- jump ahead then 32val__operand ADD R0,R0,R0,LSL #2 ;Multiply by 5 ADD R0,R14,R0,LSL #1 ;And then by 2 (* 10) BL getToken ;Load the next token B %30val__readSimple ;Keep on reading more ; --- Finished reading a number --- 35val__operand BL val__stackNumber ;Put a number on the stack B %90val__operand ;Jump ahead ; --- Read an indirection operator --- 40val__operand MOV R0,#0 ;Get the offset ready BL val__stackNumber ;Put it on the stack BL val__stackToken ;And put operator on too BL getToken ;Get the next token B %00val__operand ;Need another operand ; --- Deal with unary signs --- 50val__operand CMP R9,#'-' ;Is is a unary minus BLEQ val__stackToken ;Yes -- put it on the stack BL getToken ;Get another token B %00val__operand ;Need another operand ; --- We have just read a '(' --- 60val__operand BL val__stackToken ;Stackit immediately BL getToken ;Get another token B %00val__operand ;Need another operand ; --- Assume it's an identifier then --- 70val__operand ADR R1,sail_misc ;Point to a nice block MOV R0,#vType_integer ;The current variable type 75val__operand SUBS R14,R9,#'_' ;Is it an underscore? SUBNE R14,R9,#'0' ;Or a number? CMP R14,#10 SUBCS R14,R9,#'A' ;Or a capital letter? CMPCS R14,#26 SUBCS R14,R9,#'a' ;Or a lowercase letter? CMPCS R14,#26 STRCCB R9,[R1],#1 ;Yes -- store it away BLCC getToken ;Read the next byte BCS %95val_readLvalue ;Ouch -- not an identifier CMP R9,#'$' ;Is it a dollar sign? MOVEQ R0,#vType_string ;It's a string now CMPNE R9,#'%' ;Or a percentage? STREQB R9,[R2],#1 ;Yes -- store it then CMPNE R9,#' ' ;Just check for a space BNE %75val_readLvalue ;Go round for more MOV R14,#0 ;The terminator STRB R14,[R1],#0 ;Store that in the var name BL getToken ;Read the next token ready ; --- The identifier name is in the buffer --- ADR R1,sail_misc ;Point to the name BL var_find ;Try to find the variable MOVCC R0,#err_unknown ;Not there, get the error BCC error_report ;And report a possible error LDR R1,[R0,#0] ;Load out the variable type LDR R0,[R0,#4] ;Load out the value CMP R1,#vType_integer ;Is it an integer? BLEQ val__stackInteger ;Yes -- stack it BLNE val__stackString ;No -- it's a string then 90val__operand LDMFD R13!,{R14} ;Load back registers ORRS PC,R14,#C_flag ;We found an operand 95val__operand LDMFD R13!,{R14} ;Load back registers BICS PC,R14,#C_flag ;No operand was found LTORG ; --- val__operator --- ; ; On entry: R7, R8, R9 == lookahead token ; R10 == pointer into tokenised buffer ; R11 == evaluation stack pointer ; R12 == anchor pointer ; ; On exit: R7, R8, R9 == lookahead token ; R10 modified appropriately ; CS if operator found, ; CC otherwise ; ; Use: Reads an operator from the input, and does appropriate ; stack like things with it. ROUT val__operator STMFD R13!,{R14} ;Stack registers 00val__operator CMP R9,#')' ;Is it a close bracket? BEQ %10val__operator ;Yes -- jump ahead ; --- Make sure we recognise it --- CMP R9,#'!' ;An indirection operator? CMPNE R9,#'?' CMPNE R7,#tClass__andOp CMPNE R7,#tClass__orOp CMPNE R7,#tClass__addOp CMPNE R7,#tClass__multOp CMPNE R7,#tClass__relOp BNE %95val__operator ;Nope -- just return BL val__stackToken ;Stack this token BL getToken ;Get another one B %90val__operator ;And return success ; --- We have read a ')' --- BL val__stackToken ;Stack this token BL getToken ;Get another one B %00val__operator ;We expect another operator 90val__operator LDMFD R13!,{R14} ;Load back registers ORRS PC,R14,#C_flag ;We found an operand 95val__operator LDMFD R13!,{R14} ;Load back registers BICS PC,R14,#C_flag ;No operand was found LTORG ;----- Workspace ------------------------------------------------------------ val__precTable DCD val__andOp-val__precTable DCD 0 DCD 0 DCD 0 DCD val__multOp-val__precTable DCD val__orOp-val__precTable DCD 0 DCD val__relOp-val__precTable DCD val__addOp-val__precTable DCD 0 ; --- The precedence tables --- ; ; Each byte indicates whether or not the given type of ; toke has a higher or lower precedence than another type. ; The order of the bytes is: ; ; and,-,-,-,mult,or,-,-,rel,add,- val__andOp DCB 0, 0, 0, 0,-1, 1, 0, 0,-1,-1, 0 val__multOp DCB 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0 val__orOp DCB -1, 0, 0, 0,-1, 0, 0, 0,-1,-1, 0 val__relOp DCB 1, 0, 0, 0,-1, 1, 0, 0, 0,-1, 0 val__addOp DCB 1, 0, 0, 0,-1, 1, 0, 0, 1, 0, 0 ;----- That's all, folks ---------------------------------------------------- END