📄 token.c
字号:
/* $XConsortium: token.c,v 1.2 91/10/10 11:19:55 rws Exp $ *//* Copyright International Business Machines,Corp. 1991 * All Rights Reserved * * License to use, copy, modify, and distribute this software * and its documentation for any purpose and without fee is * hereby granted, provided that the above copyright notice * appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, * and that the name of IBM not be used in advertising or * publicity pertaining to distribution of the software without * specific, written prior permission. * * IBM PROVIDES THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF * THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE QUALITY AND * PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF * THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM) ASSUMES * THE ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN * NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. *//* Authors: Sig Nin & Carol Thompson IBM Almaden Research Laboratory */#include "types.h"#include "t1stdio.h"#include "util.h"#include "digit.h"#include "token.h"#include "tokst.h"#include "hdigit.h" /* * ------------------------------------------------------------------- * Globals * ------------------------------------------------------------------- */ extern int T1Getc(F_FILE * ), T1Ungetc( int,F_FILE *);/* These variables are set by the caller */char *tokenStartP; /* Pointer to token buffer in VM */char *tokenMaxP; /* Pointer to last byte in buffer + 1 */ /* These variables are set by TOKEN */int tokenLength; /* Characters in token */boolean tokenTooLong; /* Token too long for buffer */int tokenType; /* Type of token identified */psvalue tokenValue; /* Token value */ /* * ------------------------------------------------------------------- * Private variables * ------------------------------------------------------------------- */ static FILE *inputFileP; /* Current input file */ /* Token */static char *tokenCharP; /* Pointer to next character in token */ /* * ------------------------------------------------------------------- * Private routines for manipulating numbers * ------------------------------------------------------------------- */ #define Exp10(e) \((e) == 0\ ? (DOUBLE)(1.0)\ : (-64 <= (e) && (e) <= 63\ ? Exp10T[(e)+64]\ : P10(e)\ )\) static DOUBLE Exp10T[128] = { 1e-64, 1e-63, 1e-62, 1e-61, 1e-60, 1e-59, 1e-58, 1e-57, 1e-56, 1e-55, 1e-54, 1e-53, 1e-52, 1e-51, 1e-50, 1e-49, 1e-48, 1e-47, 1e-46, 1e-45, 1e-44, 1e-43, 1e-42, 1e-41, 1e-40, 1e-39, 1e-38, 1e-37, 1e-36, 1e-35, 1e-34, 1e-33, 1e-32, 1e-31, 1e-30, 1e-29, 1e-28, 1e-27, 1e-26, 1e-25, 1e-24, 1e-23, 1e-22, 1e-21, 1e-20, 1e-19, 1e-18, 1e-17, 1e-16, 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29, 1e30, 1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39, 1e40, 1e41, 1e42, 1e43, 1e44, 1e45, 1e46, 1e47, 1e48, 1e49, 1e50, 1e51, 1e52, 1e53, 1e54, 1e55, 1e56, 1e57, 1e58, 1e59, 1e60, 1e61, 1e62, 1e63}; static DOUBLE P10(exponent) LONG exponent;{ DOUBLE value, power; if (exponent < 0) { power = 0.1; value = (exponent & 1 ? power : 1.0); exponent = -((exponent+1) >> 1); /* portable C for -(exponent/2) */ } else { power = 10.0; value = (exponent & 1 ? power : 1.0); exponent = exponent >> 1; } while(exponent > 0) { power *= power; if (exponent & 1) value *= power; exponent >>= 1; } return(value);} /* * ------------------------------------------------------------------- * Private routines and macros for manipulating the input * ------------------------------------------------------------------- */ /* Get next character from the input -- * */#define next_ch() (getc(inputFileP)) /* Push a character back into the input -- * * Ungetc of EOF will fail, but that's ok: the next getc will * return EOF. * * NOTE: These macros are presently written to return the character * pushed, or EOF if none was pushed. However, they are not * required to return anything in particular, and callers should * not rely on the returned value. */#define back_ch(ch) (ungetc(ch, inputFileP)) /* Push a character back into the input if it was not white space. * If it is a carriage return (\r) then check next char for * linefeed and consume them both, otherwise put next char back. * */#define back_ch_not_white(ch) \(\isWHITE_SPACE(ch)\ ? ((ch == '\r')\ ? (((ch = next_ch()) == '\n')\ ? EOF\ : back_ch(ch)\ )\ : EOF\ )\ : back_ch(ch)\) /* * ------------------------------------------------------------------- * Private routines and macros for manipulating the token buffer * ------------------------------------------------------------------- */ /* Add a character to the token * ---- use ONLY when you KNOW that this character will * be stored within the token buffer. */#define save_unsafe_ch(ch) (*tokenCharP++ = ch) /* Add a character to the token, if not too long to fit */#define save_ch(ch) \((tokenCharP < tokenMaxP)\ ? save_unsafe_ch(ch)\ : (tokenTooLong = TRUE)\) /* * ------------------------------------------------------------------- * Action Routines * * These routines all * -- take int ch as a parameter * -- return int ch if no token was recognized, DONE otherwise * -- leave the next character in the input, if returning DONE * ------------------------------------------------------------------- */ #define DONE (256) /* Get the next input character */static int next_char(ch) int ch;{ return(next_ch());} /* Add character to token */static int add_char(ch) int ch;{ save_ch(ch); return(next_ch());} /* ------------------------------------------------------------------- * Skip white space and comments */ /* Skip white space */static int skip_space(ch) int ch;{ do { ch = next_ch(); } while(isWHITE_SPACE(ch)); return(ch);} /* Skip comments */static int skip_comment(ch) int ch;{ do { ch = next_ch(); } while(isCOMMENT(ch)); return(ch);} /* ------------------------------------------------------------------- * Collect value elements for a number */ /* decimal integer or real number mantissa */static int m_sign;static LONG m_value;static LONG m_scale; /* real number exponent */static int e_sign;static LONG e_value;static LONG e_scale; /* radix number */static LONG r_base;static LONG r_value;static LONG r_scale; static int add_sign(ch) int ch;{ m_sign = ch; save_unsafe_ch(ch); return(next_ch());} static int add_1st_digits(ch) int ch;{ m_sign = '+'; return(add_digits(ch));} static int add_digits(ch) int ch;{ LONG value, p_value, scale; int digit; /* On entry, expect m_sign to be set to '+' or '-'; * ch is a decimal digit. * Expect at most one character saved at this point, * a sign. This routine will save up to 10 more * characters without checking the buffer boundary. */ value = ch - '0'; save_unsafe_ch(ch); ch = next_ch(); while(isDECIMAL_DIGIT(ch) && value < (MAX_INTEGER/10)) { value = (value << 3) + (value << 1) + (ch - '0'); save_unsafe_ch(ch); ch = next_ch(); } /* Quick exit for small integers -- * |x| <= 10*((MAX_INTEGER/10)-1)+9 * |x| <= 2,147,483,639 for 32 bit integers */ if (isNUMBER_ENDER(ch)) { back_ch_not_white(ch); tokenValue.integer = (m_sign == '-' ? -value : value); tokenType = TOKEN_INTEGER; return(DONE); } /* Handle additional digits. Beyond the boundary case, * 10*(MAX_INTEGER/10) <= |number| <= MAX_INTEGER * just count the digits: the number is too large to * represent as an integer and will be returned as a real. * The mantissa of a real holds fewer bits than an integer. */ p_value = value; value = (m_sign == '-' ? -value : value); scale = 0; if (isDECIMAL_DIGIT(ch)) { /* Handle the boundary case */ if (p_value == (MAX_INTEGER/10)) { digit = ch - '0'; /* Must handle positive and negative values separately */ /* for 2's complement arithmetic */ if (value > 0) { if (digit <= MAX_INTEGER%10) value = (value << 3) + (value << 1) + digit; else ++scale; /* Too big, just count it */ } else { /* Use positive % operands for portability */ if (digit <= -(MIN_INTEGER+10)%10) value = (value << 3) + (value << 1) - digit; else ++scale; /* Too big, just count it */ } } else ++scale; /* Not boundary case, just count digit */ save_unsafe_ch(ch); ch = next_ch(); /* Continue scanning digits, but can't store them */ while(isDECIMAL_DIGIT(ch)) { ++scale; save_ch(ch); ch = next_ch(); } } /* Continue from here scanning radix integer or real */ m_value = value; m_scale = scale; /* Initialize for possible real */ e_sign = '+'; e_value = 0; e_scale = 0; return(ch);} static int add_1st_decpt(ch) int ch;{ m_sign = '+'; return(add_decpt(ch));} static int add_decpt(ch) int ch;{ /* On entry, expect m_sign to be set to '+' or '-' */ m_value = 0; m_scale = 0; save_unsafe_ch(ch); return(next_ch());} static int add_fraction(ch) int ch;{ LONG value, scale; int digit; /* On entry, expect m_value and m_scale to be initialized, * and m_sign to be set to '+' or '-'. Expect m_value and m_sign * to be consistent (this is not checked). */ value = m_value; scale = m_scale; /* Scan leading zeroes */ if (value == 0) { while(ch == '0') { --scale; save_ch(ch); ch = next_ch(); } /* Scan first significant digit */ if (isDECIMAL_DIGIT(ch)) { --scale; value = ch - '0'; value = (m_sign == '-' ? -value : value); save_ch(ch); ch = next_ch(); } else /* no significant digits -- number is zero */ scale = 0; } /* value != 0 || value == 0 && !isDECIMAL_DIGIT(ch) */ /* Scan additional significant digits */ if (isDECIMAL_DIGIT(ch)) { if (value > 0) { while(isDECIMAL_DIGIT(ch) && value < (MAX_INTEGER/10)) { --scale; value = (value << 3) + (value << 1) + (ch - '0'); save_ch(ch); ch = next_ch(); } /* Check boundary case */ if (isDECIMAL_DIGIT(ch) && value == (MAX_INTEGER/10)) { digit = ch - '0'; if (digit <= MAX_INTEGER%10) { --scale; value = (value << 3) + (value << 1) + digit; save_ch(ch); ch = next_ch(); } } } else { /* value < 0 */ while(isDECIMAL_DIGIT(ch) && value > -(-(MIN_INTEGER+10)/10+1)) { /* Use positive / operands for portability */ --scale; value = (value << 3) + (value << 1) - (ch - '0'); save_ch(ch); ch = next_ch(); } /* Check boundary case */ if (isDECIMAL_DIGIT(ch) && value == -(-(MIN_INTEGER+10)/10+1)) { digit = ch - '0'; if (digit <= -(MIN_INTEGER+10)%10) { /* Use positive % operands for portability */ --scale; value = (value << 3) + (value << 1) - digit; save_ch(ch); ch = next_ch(); } } } /* Additional digits can be discarded */ while(isDECIMAL_DIGIT(ch)) { save_ch(ch); ch = next_ch(); } } /* Store results */ m_value = value; m_scale = scale; /* Initialize for possible real */ e_sign = '+'; e_value = 0; e_scale = 0; return(ch);} static int add_e_sign(ch) int ch;{ e_sign = ch; save_ch(ch); return(next_ch());} static int add_exponent(ch) int ch;{ LONG value, p_value; LONG scale = 0; int digit; /* On entry, expect e_sign to be set to '+' or '-' */ value = ch - '0'; save_ch(ch); ch = next_ch(); while(isDECIMAL_DIGIT(ch) && value < (MAX_INTEGER/10)) { value = (value << 3) + (value << 1) + (ch - '0'); save_ch(ch); ch = next_ch(); } p_value = value; value = (e_sign == '-' ? -value : value); /* Handle additional digits. Beyond the boundary case, * 10*(MAX_INTEGER/10) <= |number| <= MAX_INTEGER * just count the digits: the number is too large to * represent as an integer. */ if (isDECIMAL_DIGIT(ch)) { /* Examine boundary case */ if (p_value == (MAX_INTEGER/10)) { digit = ch - '0'; /* Must handle positive and negative values separately */ /* for 2's complement arithmetic */ if (value > 0) { if (digit <= MAX_INTEGER%10) value = (value << 3) + (value << 1) + digit; else ++scale; /* Too big, just count it */ } else { /* Use positive % operands for portability */ if (digit <= -(MIN_INTEGER+10)%10) value = (value << 3) + (value << 1) - digit; else ++scale; /* Too big, just count it */ } } else ++scale; /* Not boundary case, just count digit */ save_ch(ch); ch = next_ch(); /* Continue scanning digits, but can't store any more */ while(isDECIMAL_DIGIT(ch)) { ++scale; save_ch(ch); ch = next_ch(); } } /* Store results */ e_value = value; e_scale = scale; return(ch);} static int add_radix(ch) int ch;{ if (2 <= m_value && m_value <= 36 && m_scale == 0) { r_base = m_value; save_ch(ch); return(next_ch()); } else { /* Radix invalid, complete a name token */ return(AAH_NAME(ch)); }} static int add_r_digits(ch) int ch;{ ULONG value; LONG radix, scale; int digit; /* NOTE: The syntax of a radix number allows only for * values of zero or more. The value will be stored as * a 32 bit integer, which PostScript then interprets * as signed. This means, for example, that the numbers: * * 8#37777777777 * 10#4294967295 * 16#FFFFFFFF * 36#1Z141Z3 * * are all interpreted as -1. This routine implements this * idea explicitly: it accumulates the number's value * as unsigned, then casts it to signed when done. */ /* Expect r_base to be initialized */ radix = r_base; value = 0; scale = 0; /* Scan leading zeroes */ while(ch == '0') { save_ch(ch); ch = next_ch(); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -