/** * Copyright (c) 1985 Sun Microsystems, Inc. * Copyright (c) 1980 The Regents of the University of California. * Copyright (c) 1976 Board of Trustees of the University of Illinois. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley, the University of Illinois, * Urbana, and Sun Microsystems, Inc. The name of either University * or Sun Microsystems may not be used to endorse or promote products * derived from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ /* * Here we have the token scanner for indent. It scans off one token and * puts it in the global variable "token". It returns a code, indicating the * type of token scanned. */ #define PUBLIC extern #include #include #include "globs.h" #include "codes.h" #include "proto.h" #define alphanum 1 #define opchar 3 struct templ { char *rwd; int rwcode; }; struct templ specials[100] = { "switch", 1, "case", 2, "break", 0, "struct", 3, "union", 3, "enum", 3, "default", 2, "int", 4, "char", 4, "float", 4, "double", 4, "long", 4, "short", 4, "typedef", 4, "unsigned", 4, "register", 4, "static", 4, "global", 4, "extern", 4, "void", 4, "goto", 0, "return", 0, "if", 5, "while", 5, "for", 5, "else", 6, "do", 6, "sizeof", 7, 0, 0 }; char chartype[128] = { /* this is used to facilitate the decision of what type (alphanumeric, operator) each character is */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 3, 3, 0, 0, 0, 3, 3, 0, 3, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 3, 3, 3, 3, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 3, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 3, 0, 3, 0 }; int lexi() { register char *tok; /* local pointer to next char in token */ int unary_delim; /* this is set to 1 if the current token forces a following operator to be unary */ static int last_code; /* the last token type returned */ static int l_struct; /* set to 1 if the last token was 'struct' */ int code; /* internal code to be returned */ char qchar; /* the delimiter character for a string */ tok = token; /* point to start of place to save token */ unary_delim = false; ps.col_1 = ps.last_nl; /* tell world that this token started in column 1 iff the last thing scanned was nl */ ps.last_nl = false; while (*buf_ptr == ' ' || *buf_ptr == '\t') { /* get rid of blanks */ ps.col_1 = false; /* leading blanks imply token is not in column 1 */ if (++buf_ptr >= buf_end) fill_buffer(); } /* Scan an alphanumeric token */ if (chartype[*buf_ptr] == alphanum || (buf_ptr[0] == '.' && isdigit(buf_ptr[1]))) { /* we have a character or number */ register char *j; /* used for searching thru list of reserved words */ register struct templ *p; if (isdigit(*buf_ptr) || (buf_ptr[0] == '.' && isdigit(buf_ptr[1]))) { int seendot = 0, seenexp = 0; if (*buf_ptr == '0' && (buf_ptr[1] == 'x' || buf_ptr[1] == 'X')) { *tok++ = *buf_ptr++; *tok++ = *buf_ptr++; while (isxdigit(*buf_ptr)) *tok++ = *buf_ptr++; } else while (1) { if (*buf_ptr == '.') if (seendot) break; else seendot++; *tok++ = *buf_ptr++; if (!isdigit(*buf_ptr) && *buf_ptr != '.') if ((*buf_ptr != 'E' && *buf_ptr != 'e') || seenexp) break; else { seenexp++; seendot++; *tok++ = *buf_ptr++; if (*buf_ptr == '+' || *buf_ptr == '-') *tok++ = *buf_ptr++; } } if (*buf_ptr == 'L' || *buf_ptr == 'l') *tok++ = *buf_ptr++; } else while (chartype[*buf_ptr] == alphanum) { /* copy it over */ *tok++ = *buf_ptr++; if (buf_ptr >= buf_end) fill_buffer(); } *tok++ = '\0'; while (*buf_ptr == ' ' || *buf_ptr == '\t') { /* get rid of blanks */ if (++buf_ptr >= buf_end) fill_buffer(); } ps.its_a_keyword = false; ps.sizeof_keyword = false; if (l_struct) { /* if last token was 'struct', then this token should be treated as a declaration */ l_struct = false; last_code = ident; ps.last_u_d = true; return (decl); } ps.last_u_d = false; /* Operator after indentifier is binary */ last_code = ident; /* Remember that this is the code we will return */ /* This loop will check if the token is a keyword. */ for (p = specials; (j = p->rwd) != 0; p++) { tok = token; /* point at scanned token */ if (*j++ != *tok++ || *j++ != *tok++) continue; /* This test depends on the fact that identifiers are always at least 1 character long (ie. the first two bytes of the identifier are always meaningful) */ if (tok[-1] == 0) break; /* If its a one-character identifier */ while (*tok++ == *j) if (*j++ == 0) goto found_keyword; /* I wish that C had a multi-level break... */ } if (p->rwd) { /* we have a keyword */ found_keyword: ps.its_a_keyword = true; ps.last_u_d = true; switch (p->rwcode) { case 1: /* it is a switch */ return (swstmt); case 2: /* a case or default */ return (casestmt); case 3: /* a "struct" */ if (ps.p_l_follow) break; /* inside parens: cast */ l_struct = true; /* Next time around, we will want to know that we have had a 'struct' */ case 4: /* one of the declaration keywords */ if (ps.p_l_follow) { ps.cast_mask |= 1 << ps.p_l_follow; break; /* inside parens: cast */ } last_code = decl; return (decl); case 5: /* if, while, for */ return (sp_paren); case 6: /* do, else */ return (sp_nparen); case 7: ps.sizeof_keyword = true; default: /* all others are treated like any other identifier */ return (ident); } /* end of switch */ } /* end of if (found_it) */ if (*buf_ptr == '(' && ps.tos <= 1 && ps.ind_level == 0) { register char *tp = buf_ptr; while (tp < buf_end) if (*tp++ == ')' && *tp == ';') goto not_proc; strncpy(ps.procname, token, sizeof ps.procname - 1); ps.in_par_decl = 1; not_proc:; } /* The following hack attempts to guess whether or not the current token is in fact a declaration keyword -- one that has been typedefd */ if (((*buf_ptr == '*' && buf_ptr[1] != '=') || isalpha(*buf_ptr) || *buf_ptr == '_') && !ps.p_l_follow && !ps.block_init && (ps.last_token == rparen || ps.last_token == semicolon || ps.last_token == decl || ps.last_token == lbrace || ps.last_token == rbrace)) { ps.its_a_keyword = true; ps.last_u_d = true; last_code = decl; return decl; } if (last_code == decl) /* if this is a declared variable, then following sign is unary */ ps.last_u_d = true; /* will make "int a -1" work */ last_code = ident; return (ident); /* the ident is not in the list */ } /* end of procesing for alpanum character */ /* l l l Scan a non-alphanumeric token */ *tok++ = *buf_ptr; /* if it is only a one-character token, it is moved here */ *tok = '\0'; if (++buf_ptr >= buf_end) fill_buffer(); switch (*token) { case '\n': unary_delim = ps.last_u_d; ps.last_nl = true; /* remember that we just had a newline */ code = (had_eof ? 0 : newline); /* if data has been exausted, the newline is a dummy, and we should return code to stop */ break; case '\'': /* start of quoted character */ case '"': /* start of string */ qchar = *token; if (troff) { tok[-1] = '`'; if (qchar == '"') *tok++ = '`'; tok = chfont(&bodyf, &stringf, tok); } do { /* copy the string */ while (1) { /* move one character or [/] */ if (*buf_ptr == '\n') { printf("%d: Unterminated literal\n", line_no); goto stop_lit; } *tok = *buf_ptr++; if (buf_ptr >= buf_end) fill_buffer(); if (had_eof || ((tok - token) > (bufsize - 2))) { printf("Unterminated literal\n"); ++tok; goto stop_lit; /* get outof literal copying loop */ } if (*tok == BACKSLASH) { /* if escape, copy extra char */ if (*buf_ptr == '\n') /* check for escaped newline */ ++line_no; if (troff) { *++tok = BACKSLASH; if (*buf_ptr == BACKSLASH) *++tok = BACKSLASH; } *++tok = *buf_ptr++; ++tok; /* we must increment this again because we copied two chars */ if (buf_ptr >= buf_end) fill_buffer(); } else break; /* we copied one character */ } /* end of while (1) */ } while (*tok++ != qchar); if (troff) { tok = chfont(&stringf, &bodyf, tok - 1); if (qchar == '"') *tok++ = '\''; } stop_lit: code = ident; break; case ('('): case ('['): unary_delim = true; code = lparen; break; case (')'): case (']'): code = rparen; break; case '#': unary_delim = ps.last_u_d; code = preesc; break; case '?': unary_delim = true; code = question; break; case (':'): code = colon; unary_delim = true; break; case (';'): unary_delim = true; code = semicolon; break; case ('{'): unary_delim = true; /* if (ps.in_or_st) ps.block_init = 1; */ code = ps.block_init ? lparen : lbrace; break; case ('}'): unary_delim = true; code = ps.block_init ? rparen : rbrace; break; case 014: /* a form feed */ unary_delim = ps.last_u_d; ps.last_nl = true; /* remember this so we can set 'ps.col_1' right */ code = form_feed; break; case (','): unary_delim = true; code = comma; break; case '.': unary_delim = false; code = period; break; case '-': case '+': /* check for -, +, --, ++ */ code = (ps.last_u_d ? unary_op : binary_op); unary_delim = true; if (*buf_ptr == token[0]) { /* check for doubled character */ *tok++ = *buf_ptr++; /* buffer overflow will be checked at end of loop */ if (last_code == ident || last_code == rparen) { code = (ps.last_u_d ? unary_op : postop); /* check for following ++ or -- */ unary_delim = false; } } else if (*buf_ptr == '=') /* check for operator += */ *tok++ = *buf_ptr++; else if (*buf_ptr == '>') { /* check for operator -> */ *tok++ = *buf_ptr++; if (!ptr_binop) { unary_delim = false; code = unary_op; ps.want_blank = false; } } break; /* buffer overflow will be checked at end of switch */ case '=': if (ps.in_or_st) ps.block_init = 1; #ifdef undef if (chartype[*buf_ptr] == opchar) { /* we have two char assignment */ tok[-1] = *buf_ptr++; if ((tok[-1] == '<' || tok[-1] == '>') && tok[-1] == *buf_ptr) *tok++ = *buf_ptr++; *tok++ = '='; /* Flip =+ to += */ *tok = 0; } #else if (*buf_ptr == '=') { /* == */ *tok++ = '='; /* Flip =+ to += */ buf_ptr++; *tok = 0; } #endif code = binary_op; unary_delim = true; break; /* can drop thru!!! */ case '>': case '<': case '!': /* ops like <, <<, <=, !=, etc */ if (*buf_ptr == '>' || *buf_ptr == '<' || *buf_ptr == '=') { *tok++ = *buf_ptr; if (++buf_ptr >= buf_end) fill_buffer(); } if (*buf_ptr == '=') *tok++ = *buf_ptr++; code = (ps.last_u_d ? unary_op : binary_op); unary_delim = true; break; default: if (token[0] == '/' && *buf_ptr == '*') { /* it is start of comment */ *tok++ = '*'; if (++buf_ptr >= buf_end) fill_buffer(); code = comment; unary_delim = ps.last_u_d; break; } while (*(tok - 1) == *buf_ptr || *buf_ptr == '=') { /* handle ||, &&, etc, and also things as in int *****i */ *tok++ = *buf_ptr; if (++buf_ptr >= buf_end) fill_buffer(); } code = (ps.last_u_d ? unary_op : binary_op); unary_delim = true; } /* end of switch */ if (code != newline) { l_struct = false; last_code = code; } if (buf_ptr >= buf_end) /* check for input buffer empty */ fill_buffer(); ps.last_u_d = unary_delim; *tok = '\0'; /* null terminate the token */ return (code); } /* * Add the given keyword to the keyword table, using val as the keyword type */ void addkey(key, val) char *key; int val; { register struct templ *p = specials; while (p->rwd) if (p->rwd[0] == key[0] && strcmp(p->rwd, key) == 0) return; else p++; if (p >= specials + sizeof specials / sizeof specials[0]) return; /* For now, table overflows are silently ignored */ p->rwd = key; p->rwcode = val; p[1].rwd = 0; p[1].rwcode = 0; return; }