Blame | Last modification | View Log | RSS feed
/*CPP V5 -- Token parsing routines.source: tok.cstarted: October 7, 1985version: May 26, 1988; July 21, 1988Written by Edward K. Ream.This software is in the public domain.See the read.me file for disclaimer and other information.*/#include "cpp.h"/* Declare internal variables and routines. */static int is_base_digit (int);static void scan_number (int);static en_tokens t_int (void);/*Return >= 0 if ch is a digit in the indicated base.Otherwise, return -1.*/static intis_base_digit(base)int base;{TRACECH("is_base_digit");if (ch >= '0' && ch <= '9') {RETURN_INT("is_base_digit", ch - '0');}else if (base != 16) {RETURN_INT("is_base_digit", -1);}else if (ch >= 'a' && ch <= 'f') {RETURN_INT("is_base_digit", ch - 'a' + 10);}else if (ch >= 'A' && ch <= 'F') {RETURN_INT("is_base_digit", ch - 'A' + 10);}else {RETURN_INT("is_base_digit", -1);}}/*Get value of a string of digits into t_value.Continue until a non base digit is found.*/static voidscan_number(base)int base;{int result;TRACECH("scan_number");t_value = 0;while ( (result = is_base_digit(base)) != -1) {t_value = ((long)base * t_value) + (long) result;sysnext();}LEAVE("scan_number");}/*Output a comment. Allow nested comments if nest_flag is TRUE.Surprisingly, this routine needs to be as fast as possible.*/voidcopy_comment(){register int clevel;int start_line;char line [LONG_DIGITS];TRACECH("copy_comment");/* Save starting line number for run-on comments. */start_line = t_line;clevel = 1;for (;;) {switch (ch) {case END_FILE:conv2s(start_line, line);err3("File ends in a comment starting at line ",line, ".");RETURN_VOID("copy_comment");case '\n':/* Keep track of line numbering. */bump_line();sysnlput();sysnext();continue;case '/':syscput(ch);sysnext();if (ch == '*') {syscput(ch);sysnext();if (nest_flag) {clevel++;}}continue;case '*':syscput(ch);sysnext();if (ch == '/') {syscput(ch);sysnext();if (--clevel == 0) {RETURN_VOID("copy_comment");}}continue;default:syscput(ch);sysnext();}}}voidskip_comment(){register int clevel;int start_line;char line [LONG_DIGITS];TRACECH("skip_comment");/* Save starting line number for run-on comments. */start_line = t_line;clevel = 1;for (;;) {switch (ch) {case END_FILE:conv2s(start_line, line);err3("File ends in a comment starting at line ",line, ".");RETURN_VOID("skip_comment");case EORT:conv2s(start_line, line);err3("Macro arg ends in a comment starting at line ",line, ".");RETURN_VOID("skip_comment");case '\n':/* Keep track of line numbering. */bump_line();sysnext();continue;case '/':sysnext();if (ch == '*') {sysnext();if (nest_flag) {clevel++;}}continue;case '*':sysnext();if (ch == '/') {sysnext();if (--clevel == 0) {RETURN_VOID("skip_comment");}}continue;default:sysnext();}}}/*Copy an identifier into symbol[] and its length in the global t_length.Surprisingly, this routine should be as fast as possible.*/voidt_id(symbol, max_length)char * symbol;int max_length;{int length = 0;TRACEPB("t_id", printf("(%p, %d)\n", symbol, max_length));max_length--;while (isid2(ch) && length < max_length) {*symbol++ = ch;length++;sysnext();}*symbol = '\0';t_length = length;if (length >= max_length) {error("Identifier too long.");}LEAVE("t_id");}/*Parse an integer constant (octal, decimal or hexadecimal) or float.Put the value in t_value if it is an integer.dot_flag is TRUE if a decimal point has been seen.Return the token type (INT_TOK, LONG_TOK, FLOAT_TOK).Legal integer forms: ddd, 0ddd, 0xdddLegal float forms: xxx.yyyE+zzz+-zzz is optionalone of xxx and yyy may be omittedone of . and E may be omitted*/en_tokenst_number(dot_flag)bool dot_flag;{en_tokens result;bool need_exp = FALSE;TRACECH("t_number");/* Defaults. */t_value = 0;if (dot_flag) {goto frac_part;}/* Integer part. */result = t_int();if (ch == '.') {sysnext();goto frac_part;}else if (ch == 'e' || ch == 'E') {goto exp_part;}else {RETURN_INT("t_number", result);}/* Fraction part. */frac_part:t_int();exp_part:if (ch == 'e' || ch == 'E') {need_exp = TRUE;sysnext();}if (ch == '+' || ch == '-') {need_exp = TRUE;sysnext();}if (ch >= '0' && ch <= '9') {t_int();}else if (need_exp) {error("Ill formed floating constant.");}if (ch == 'l' || ch == 'L' || ch == 'f' || ch == 'F') {sysnext();}RETURN_INT("t_number", FLOAT_TOK);}static en_tokenst_int(){TRACECH("t_int");/* Leading 0 or 0x changes base. */if (ch == '0') {sysnext();if (ch == 'x' || ch == 'X') {sysnext();scan_number(16);}else if (isdigit(ch)) {scan_number(8);}else {/* Lone '0'. */t_value = 0;}}else {scan_number(10);}if (ch == 'l' || ch == 'L') {sysnext();if(ch == 'u' || ch == 'U') {sysnext();}RETURN_INT("t_int", LONG_TOK);}else if (ch == 'u' || ch == 'U') {sysnext();if (ch == 'l' || ch == 'L') {RETURN_INT("t_int", LONG_TOK);}else {RETURN_INT("t_int", INT_TOK);}}else {RETURN_INT("t_int", INT_TOK);}}/*Copy a string into out[] and puts its length in the global t_length.Copy the opening or closing delimiters if the copy_flag is TRUE.This is used to parse both strings and character constants.*/voidt_string(out, max_out, copy_flag)register char * out; /* The output buffer. */int max_out; /* The size of out[]. */bool copy_flag; /* Copy the delimiters if copy_flag is TRUE. */{register int length;int start_line;char * start_string;char line [10];int delim;TRACECH("t_string");/* Save starting line number for error messages. */start_line = t_line;start_string = out;/* Handle the opening single or double quote */delim = ch;sysnext();length = 0;if (copy_flag) {*out++ = delim;length++;}max_out--;while (length < max_out) {switch(ch) {case END_FILE:case '\n':goto runon1;case '"':case '\'':if (ch == delim) {sysnext();if(copy_flag) {*out++ = delim;length++;}*out++ = '\0';t_length = length;TRACEP("t_string", printf("<%s>\n",start_string));RETURN_VOID("t_string");}else{*out++ = ch;length++;sysnext();}continue;case '\\':sysnext();if (ch == END_FILE) {goto runon1;}else if (ch == '\n') {/* Ignore back slash and newline. */t_line++;sysnext();}else {*out++ = '\\';*out++ = ch;length += 2;sysnext();}continue;default:*out++ = ch;length++;sysnext();}}conv2s(start_line, line);err3("String starting at line ", line, " is too long.");*out = '\0';t_length = length;RETURN_VOID("t_string");runon1:*out = '\0';err2("String crosses a line: ", start_string);t_length = length;LEAVE("t_string");}/*Parse a string (including delimiters) from in[] to out.Return the length of the ORIGINAL string.*/intin_string(in, out, max_out)char * in; /* The output buffer */char * out; /* The output buffer. */int max_out; /* The size of out[]. */{register int length;int start_line;char * start_string;char line [10];int delim;TRACEPB("in_string", printf("(<%s>, %p, %d)\n",in, out, max_out));/* Save starting line number for error messages. */start_line = t_line;start_string = out;/* Copy the opening single or double quote */*out++ = delim = *in++;length = 1;max_out--;while (length < max_out) {switch(*in) {case END_FILE:case '\n':goto runon1;case '"':case '\'':if (*in == delim) {*out++ = *in++;*out++ = '\0';length++;RETURN_INT("in_string", length);}else{*out++ = *in++;length++;}continue;case '\\':in++;if (*in == END_FILE) {goto runon1;}else if (*in == '\n') {/* Ignore back slash and newline. */t_line++;in++;/* Keep track of ORIGINAL length. */length += 2;}else {*out++ = '\\';*out++ = *in++;length += 2;}continue;default:*out++ = *in++;length++;}}conv2s(start_line, line);err3("Strinized argument starting at line ", line, " is too long.");*out = '\0';RETURN_INT("in_string", length);runon1:*out = '\0';err2("Stringized argument crosses a line: ", start_string);RETURN_INT("in_string", length);}