home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The C Users' Group Library 1994 August
/
wc-cdrom-cusersgrouplibrary-1994-08.iso
/
vol_300
/
319_02
/
tok.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-06-18
|
9KB
|
531 lines
/*
CPP V5 -- Token parsing routines.
source: tok.c
started: October 7, 1985
version: May 26, 1988; July 21, 1988
Written 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 int
is_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 void
scan_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.
*/
void
copy_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();
}
}
}
void
skip_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.
*/
void
t_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, 0xddd
Legal float forms: xxx.yyyE+zzz
+-zzz is optional
one of xxx and yyy may be omitted
one of . and E may be omitted
*/
en_tokens
t_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_tokens
t_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.
*/
void
t_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.
*/
int
in_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);
}