📄 scan.c
字号:
int sc_fmtlen (const char *s, int *len){ /* --- length of a formatted name */ int n = 0, k = 0; /* number of (additional) characters */ int q = 0; /* quote flag (default: no quotes) */ assert(s); /* check the function arguments */ while (*s) { /* while not at end of name */ n++; /* count character */ switch (_scftab[(unsigned char)*s++]) { case 0: break; case 1: q = 2; break; case 2: k += 3; q = 2; break; default: k += 1; q = 2; break; } /* sum additional characters and */ } /* set quote flag (if necessary) */ if (len) *len = n; /* store normal length and */ return n +k +q; /* return length of scanable form */} /* sc_fmtlen() *//*--------------------------------------------------------------------*/int sc_format (char *dst, const char *src, int quotes){ /* --- format name in scanable form */ char *d; const char *s; /* to traverse buffer and name */ int c, cls; /* character and character class */ int t; /* temporary buffer */ assert(dst && src); /* check the function arguments */ if (!*src) quotes = 1; /* an empty name needs quotes */ if (!quotes) { /* if quotes are not mandatory, */ for (s = src; *s; ) /* traverse the string to convert */ if (_scftab[(unsigned char)*s++] != 0) { quotes = 1; break; } /* if a character needs quotes, */ } /* set the quotes flag and abort */ d = dst; /* get the destination and */ if (quotes) *d++ = '"'; /* store a quote if necessary */ while (*src) { /* traverse the characters */ c = (unsigned char)*src++;/* get the next character */ cls = _scftab[c]; /* and its character class */ if (cls < 2) /* if it is a normal character, */ *d++ = c; /* just store it */ else if (cls > 2) { /* if it is an ANSI escape character, */ *d++ = '\\'; *d++ = cls;} /* store it as '\c' */ else { /* if it is any other character */ *d++ = '\\'; *d++ = 'x'; t = c >> 4; *d++ = (t > 9) ? (t -10 +'a') : (t +'0'); t = c & 0xf; *d++ = (t > 9) ? (t -10 +'a') : (t +'0'); } /* store the character code */ } /* as a hexadecimal number */ if (quotes) *d++ = '"'; /* store the closing quote */ *d = '\0'; /* and terminate the string */ return (int)(d -dst); /* return the length of the result */} /* sc_format() *//*--------------------------------------------------------------------*/#ifdef SC_SCANSCAN* sc_create (const char *fname){ /* --- create a scanner */ const char *fn = fname; /* buffer for filename */ SCAN *scan; /* created scanner */ if (!fn || !*fn) fname = "<stdin>"; scan = (SCAN*)malloc(sizeof(SCAN) +strlen(fname)); if (!scan) return NULL; /* allocate memory for a scanner */ strcpy(scan->fname, fname); /* and note the file name */ if (!fn || !*fn) /* if no file name is given, */ scan->file = stdin; /* read from standard input */ else { /* if a file name is given, */ scan->file = fopen(fn,"r"); /* open the file for reading */ if (!scan->file) { free(scan); return NULL; } } scan->line = 1; /* initialize the fields */ scan->token = scan->len = scan->start = 0; scan->value = scan->buf[0]; scan->buf[0][0] = '\0'; scan->back = 0; scan->errfile = stderr; scan->msgcnt = scan->lncnt = 0; scan->msgs = NULL; return scan; /* return created scanner */} /* sc_create() *//*--------------------------------------------------------------------*/void sc_delete (SCAN *scan){ /* --- delete a scanner */ if (scan->file != stdin) fclose(scan->file); free(scan); /* close the input file and */} /* sc_delete() */ /* delete the scanner structure *//*--------------------------------------------------------------------*/int sc_next (SCAN *scan){ /* --- get next token */ int c, ccl; /* character and character class */ int quote = 0; /* quote at the start of a string */ int ec = 0; /* escaped character */ int state = 0; /* state of automaton */ int level = 0; /* comment nesting level */ char *p; /* to traverse the scan buffer */ char *end; /* end of the scan buffer */ if (scan->back) { /* if a step backwards has been made, */ scan->back = 0; /* clear the corresponding flag, */ return _swap(scan); /* swap back the token information, */ } /* and return the current token */ scan->pline = scan->line; /* note the relevant information */ scan->ptoken = scan->token; /* of the current token */ scan->plen = scan->len; /* and swap scan buffers */ if (scan->value == scan->buf[0]) scan->value = p = scan->buf[1]; else scan->value = p = scan->buf[0]; end = p +SC_BUFSIZE -1; /* get the end of the scan buffer */ while (1) { /* read loop */ c = getc(scan->file); /* get character and character class */ ccl = (c < 0) ? EOF : _ccltab[c]; if (c == '\n') scan->line++; /* count the line */ switch (state) { /* evaluate state of automaton */ case S_SPACE: /* --- skip white space */ switch (ccl) { /* evaluate character category */ case C_SPACE : /* do nothing */ break; case C_LETTER: *p++ = c; state = S_ID; break; case C_DIGIT : *p++ = c; state = S_NUMDIG; break; case C_POINT : *p++ = c; state = S_NUMPT; break; case C_SIGN : *p++ = c; state = S_SIGN; break; case C_CMPOP : *p++ = c; state = S_CMPOP; break; case C_QUOTE : quote = c; state = S_STRING; break; case C_SLASH : state = S_SLASH; break; case C_ACTIVE: *p++ = c; *p = '\0'; scan->len = 1; return scan->token = c; case EOF : strcpy(p, "<eof>"); scan->len = 4; return scan->token = (ferror(scan->file)) ? E_FREAD : T_EOF; default : *p++ = c; *p = '\0'; scan->len = 1; return scan->token = E_ILLCHR; } break; case S_ID: /* --- identifier (letter read) */ if ((ccl == C_LETTER) /* if another letter */ || (ccl == C_DIGIT) /* or a digit */ || (ccl == C_POINT) /* or a decimal point */ || (ccl == C_SIGN)) { /* or a sign follows */ if (p >= end) return scan->token = E_BUFOVF; *p++ = c; break; /* buffer character */ } /* otherwise */ UNGETC(scan, c); /* put back last character, */ *p = '\0'; /* terminate string in buffer */ scan->len = (int)(p -scan->value); /* set string length */ return scan->token = T_ID; /* and return 'identifier' */ case S_NUMDIG: /* --- number (digit read) */ if (p < end) *p++ = c; /* buffer character */ else return scan->token = E_BUFOVF; if (ccl == C_DIGIT) /* if another digit follows, */ break; /* do nothing */ if (ccl == C_POINT) { /* if a decimal point follows, */ state = S_FRAC; break; } /* go to 'fraction' state */ if ((c == 'e') /* if an exponent indicator follows */ || (c == 'E')) { /* (lower- or uppercase), */ state = S_EXPIND; break; } /* go to 'exponent' state */ if ((ccl == C_LETTER) /* if a letter */ || (ccl == C_SIGN)) { /* or a sign follows, */ state = S_ID; break; /* go to 'identifier' state */ } /* otherwise */ UNGETC(scan, c); /* put back last character, */ *--p = '\0'; /* terminate string in buffer */ scan->len = (int)(p -scan->value); /* set string length */ return scan->token = T_NUM; /* and return 'number' */ case S_NUMPT: /* --- number (point read) */ if (p < end) *p++ = c; /* buffer character */ else return scan->token = E_BUFOVF; if (ccl == C_DIGIT) { /* if a digit follows, */ state = S_FRAC; break; } /* go to 'fraction' state */ if ((ccl == C_LETTER) /* if a letter */ || (ccl == C_POINT) /* or a decimal point */ || (ccl == C_SIGN)) { /* or a sign follows */ state = S_ID; break; /* go to 'identifier' state */ } /* otherwise */ UNGETC(scan, c); /* put back last character, */ *--p = '\0'; /* terminate string in buffer */ scan->len = (int)(p -scan->value); /* set string length */ return scan->token = T_ID; /* and return 'identifier' */ case S_FRAC: /* --- number (digit & point read) */ if (p < end) *p++ = c; /* buffer character */ else return scan->token = E_BUFOVF; if (ccl == C_DIGIT) /* if another digit follows, */ break; /* do nothing else */ if ((c == 'e') /* if an exponent indicator follows, */ || (c == 'E')) { /* (lower- or uppercase), */ state = S_EXPIND; break; } /* go to exponent state */ if ((ccl == C_LETTER) /* if a letter */ || (ccl == C_POINT) /* or a decimal point */ || (ccl == C_SIGN)) { /* or a sign follows, */ state = S_ID; break; /* go to 'identifier' state */ } /* otherwise */ UNGETC(scan, c); /* put back last character, */ *--p = '\0'; /* terminate string in buffer */ scan->len = (int)(p -scan->value); /* set string length */ return scan->token = T_NUM; /* and return 'number' */ case S_EXPIND: /* --- exponent (indicator read) */ if (p < end) *p++ = c; /* buffer character */ else return scan->token = E_BUFOVF; if (ccl == C_SIGN) { /* if a sign follows, */ state = S_EXPSGN; break; } /* go to 2nd 'exponent' state */ if (ccl == C_DIGIT) { /* if a digit follows, */ state = S_EXPDIG; break; } /* go to 3rd 'exponent' state */ if ((ccl == C_LETTER) /* if a letter */ || (ccl == C_POINT)) { /* or a decimal point follows */ state = S_ID; break; /* go to 'identifier' state */ } /* otherwise */ UNGETC(scan, c); /* put back last character, */ *--p = '\0'; /* terminate string in buffer */ scan->len = (int)(p -scan->value); /* set string length */ return scan->token = T_ID; /* and return 'identifier' */ case S_EXPSGN: /* --- exponent (sign read) */ if (p < end) *p++ = c; /* buffer character */ else return scan->token = E_BUFOVF; if (ccl == C_DIGIT) { /* if a digit follows, */ state = S_EXPDIG; break;} /* do nothing else */ if ((ccl == C_LETTER) /* if a letter */ || (ccl == C_POINT) /* or a decimal point */ || (ccl == C_SIGN)) { /* or a sign follows */ state = S_ID; break; /* go to 'identifier' state */ } /* otherwise */ UNGETC(scan, c); /* put back last character, */ *--p = '\0'; /* terminate string in buffer */ scan->len = (int)(p -scan->value); /* set string length */ return scan->token = T_ID; /* and return 'identifier' */ case S_EXPDIG: /* --- exponent (digit read) */ if (p < end) *p++ = c; /* buffer character */ else return scan->token = E_BUFOVF; if (ccl == C_DIGIT) /* if another digit follows, */ break; /* do nothing else */ if ((ccl == C_LETTER) /* if a letter */ || (ccl == C_POINT) /* or a decimal point */ || (ccl == C_SIGN)) { /* or a sign follows, */ state = S_ID; break; /* go to 'identifier' state */ } /* otherwise */ UNGETC(scan, c); /* put back last character, */ *--p = '\0'; /* terminate string in buffer */ scan->len = (int)(p -scan->value); /* set string length */ return scan->token = T_NUM; /* and return 'number' */ case S_SIGN: /* --- number (sign read) */ *p++ = c; /* buffer character */ if (ccl == C_DIGIT) { /* if a digit follows, */ state = S_NUMDIG; break; } /* go to 'number' state */ if (ccl == C_POINT) { /* if a decimal point follows, */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -