c·c++/c 프로그래밍

스캐너(token으로 쪼개기)

바로이순간 2013. 5. 3. 21:23

#include <stdio.h>

#include <stdlib.h>

#include <ctype.h>

#include <string.h>

typedef struct _token {

    int type;

    int value;

    char *lexeme;

} token;

token* key_or_id(FILE *fin, int x) {

    const char *keywords[12]={

        "else", "if", "int", "return", "void", "while", "char", "for", "do", "switch", "continue", "break"

    };

    token *tok;

    int i, j, n=12;

    char buf[100];

    i=0;

    while(isalpha(x)) {

        buf[i]=(char)x;

        i+=1;

        x=fgetc(fin);

    }

    buf[i]=0;

    ungetc(x, fin);

    for(i=0;i<n;++i) {

        if(strcmp(buf, keywords[i])==0) { break; }

    }

    

    tok=(token*)calloc(sizeof(token), 1);

    if(tok==NULL) {

        printf("Memory allocation failed.\n");

        return NULL;

    }

    if(i<n) {

        tok->type=1;           // keyword;

        tok->value=100+i; // 100: else 101: if ... 111: break 를 나타낸다.

    }  else {

        tok->type=2;           // identifier;

        tok->lexeme=strdup(buf);

    }

    return tok;

}

token* number(FILE *fin, int x) {

    token *tok;

    int num=0;

    while(isdigit(x)) {

        num=10*num+x-'0';

        x=fgetc(fin);

    }

    ungetc(x, fin);

    tok=(token*)calloc(sizeof(token), 1);

    if(tok==NULL) {

         printf("Memory allocation failed.\n");

        return NULL;

   }

    tok->type=3;          // number;

    tok->value=num;

    return tok;

}

token* special(FILE *fin, int x) {

    token *tok;


    tok=(token*)calloc(sizeof(token), 1);

    if(tok==NULL) {

         printf("Memory allocation failed.\n");

        return NULL;

    }

    tok->type=-1; // not defined

    tok->value=x; // 디버깅용

    switch(x) {

        case '/':

            x=fgetc(fin);

            if(x=='*') {

                tok->type=4;       // special symbol

                tok->value=11;   //   11: /*   코멘트의 시작 

            } else {

                tok->type=4;       // special symbol

                tok->value=12;   //   12: /  나눗셈 연산자

                ungetc(x, fin);

            }

            break;

        case '*':

            x=fgetc(fin);

            if(x=='/') {

                tok->type=4;       // special symbol

                tok->value=13;   //   13: */   코멘트의 끝 

            } else {

                tok->type=4;       // special symbol

                tok->value=14;   //   14: *  곱셈 연산자

                ungetc(x, fin);

            }

            break;

        case '=':

            x=fgetc(fin);

            if(x=='=') {

                tok->type=4;       // special symbol

                tok->value=15;   //   15: ==   비교 같다 

            } else {

                tok->type=4;       // special symbol

                tok->value=16;   //   16: =  대입 연산자

                ungetc(x, fin);

            }

            break;

        case '!':

            x=fgetc(fin);

            if(x=='=') {

                tok->type=4;       // special symbol

                tok->value=17;   //   17: !=   비교 다르다 

            } else {

                tok->type=4;       // special symbol

                tok->value=99;   //   99: !  에러

                ungetc(x, fin);

            }

            break;

        case '+':

            tok->type=4;          // special sysbol

            tok->value=18;      //   18: + 덧셈

            break;

        case '-':

            tok->type=4;          // special sysbol

            tok->value=19;      //   19: - 뺄셈

            break;

        case '<':

            tok->type=4;          // special sysbol

            tok->value=20;      //   20: < 작다

            break;

        case '>':

            tok->type=4;          // special sysbol

            tok->value=21;      //   21: > 크다

            break;

        case ';':

            tok->type=4;          // special sysbol

            tok->value=22;      //   22: ; 세미콜론

            break;

        case '(':

            tok->type=4;          // special sysbol

            tok->value=23;      //   23: ( 왼괄호

            break;

        case ')':

            tok->type=4;          // special sysbol

            tok->value=24;      //   24: ) 오른괄호

            break;

        case '{':

            tok->type=4;          // special sysbol

            tok->value=25;      //   25: {  왼중괄호

            break;

         case '}':

            tok->type=4;          // special sysbol

            tok->value=26;      //   26: }  오른중괄호

            break;

        case '[':

            tok->type=4;          // special sysbol

            tok->value=27;      //   27: [  왼대괄호

            break;

         case ']':

            tok->type=4;          // special sysbol

            tok->value=28;      //   28: ]  오른대괄호

            break;

    }

    return tok;

}

token* scanner(FILE *fin) {

    int x;

    while(!feof(fin)) {

        x=fgetc(fin);

        if(isalpha(x)) {

            return key_or_id(fin, x);

        } else if(isdigit(x)) {

            return number(fin, x);

        } else if(!isspace(x)) {

            return special(fin, x);

        } // white space needs to be skipped

    }

}

int main() {

    FILE *fin;

    char fname[100];

    token *ctok;


    printf("파일이름: ");

    gets(fname);

    fin=fopen(fname, "r");

    if(fin==NULL) {

        printf("Cannot open file %s\n", fname);

        return -1;

    }

    while(!feof(fin)) {

        ctok=scanner(fin);

        printf("token type = %d", ctok->type);

        if(ctok->type==1) { 

            printf(" token value=%d\n", ctok->value); 

        } else if(ctok->type==2) {

            printf(" token id = %s\n", ctok->lexeme);

        } else if(ctok->type==3) {

            printf(" token number=%d\n", ctok->value);

        } else if(ctok->type==4) {

            printf(" token kind=%d\n", ctok->value);

        } else if(ctok->value!=-1) {

            printf(" token kind=%c\n", ctok->value);

        } else {

            printf(" EOF\n");

        }

    }

    fclose(fin);


    return 0;

}