2016-08-06 2 views
1

필자의 렉서를 마무리하고 있으며, 인쇄에 문제가 있거나 올바르게 값을 할당하려고합니다. 여기 내 출력은 integer: "10"이어야하며, 문제는 lexer_num 또는 lexer_flt : (요청에 따라 더 많은 정보 포함)이라고 생각합니다. 16 진수 덤프가 무엇인지 알지 못하거나 실제로 생각하지 않습니다. 그것을 제공 할 수 있습니다. 귀하의 질문에 대한 답변을 lexer_numlexer_num에 왜 v는 음수가 필요하지 않기 때문에 음수는 파서가 아닌 렉서에서 처리되기 때문에 size_t입니다.렉스러스의 이상한 숫자

Type: "40" { 
     Line: "1" 
     Pos: "0" 
     Num: "2591542" 
     Real: "0.000000" 
     Stri: "" 
} 

코드 :

#define _CRT_SECURE_NO_WARNINGS 
#define DEBUG 0 

#include "lexer.h" 
#include "error.h" 
#include <stdlib.h> 
#include <stdio.h> 
#include <stdint.h> 
#include <ctype.h> 
#include <assert.h> 

typedef struct lextoken_t { 
    const char* str; 
    token_t type; 
} lextoken_t; 

static const lextoken_t keywords[] = { 
    // types 
    { "int", _int }, 
    { "double", _dbl }, 
    { "void", _void }, 
    { "char", _char }, 
    { "string", _str }, 
    { "bool", _bool }, 
    { "const", _const }, 
    { "struct", _struct } 
}; 

/* token_new: creates and returns a new token ptr. 
** -lexer: a ptr to the lexer. 
** -type: the token type. 
*/ 
token_t* token_new(lexer_t* lexer, tk_type type) { 
    token_t* token = malloc(sizeof(token_t)); 
    token->line = lexer->line; 
    token->pos = lexer->pos; 
    token->type = type; 
    token->integer = 0; 
    token->flt = 0; 
    token->string = NULL; 

    return token; 
} 

static void token_print(token_t* token) { 
    if (token == NULL) 
     printf("Null token"); 

    printf("Type: \"%i\" { \n", token->type); 
    printf("\tLine: \"%i\"\n", token->line); 
    printf("\tPos: \"%i\"\n", token->pos); 
    printf("\tNum: \"%i\"\n", token->integer); 
    printf("\tReal: \"%f\"\n", token->flt); 
    printf("\tStri: \"%s\"\n}\n\n", token->string); 
} 

/* lexer_look: look at the source (ahead) places infront of the lexer->ptr. 
** -lexer: a ptr to the lexer to look ahead in. 
** -ahead: how far ahead of the ptr to look. 
*/ 
static char lexer_look(lexer_t* lexer, size_t ahead) { 
    if (lexer->len < lexer->ptr + ahead) { 
     error_new(lexer->errors, 0, 0, "The lexer tried to index %d out of bounds %d", lexer->ptr + ahead, lexer->len); 
     return; 
    } 
    return lexer->src[lexer->ptr + ahead]; 
} 

static size_t can_adv(lexer_t* lexer, size_t steps) { 
    if (lexer->ptr + steps <= lexer->len) 
     return 1; 
    else 
     return 0; 
} 

/* lexer_adv: moves the lexer->ptr (steps) places. 
** -lexer: a ptr to the lexer to look ahead in. 
** -steps: how far to advance the ptr. 
*/ 
static char lexer_adv(lexer_t* lexer, size_t steps) { 

    if (!can_adv(lexer, steps)) 
     error_new(lexer->errors, 0, 0, "The lexer tried to move ptr past bounds %d with value of %d", lexer->len, lexer->ptr + steps); 
    lexer->ptr += steps; 
    return lexer->src[lexer->ptr]; 
} 

static void new_line(lexer_t* lexer) { 
    lexer->line = 0; 
    lexer->pos = 0; 
} 

static void lexer_nested(lexer_t* lexer) { 
    lexer_adv(lexer, 2); 
    char c = lexer_look(lexer, 0); 
    size_t depth = 1; 

    while (depth > 0) { 
     if (!can_adv(lexer, 1)) 
      error_new(lexer->errors, lexer->line, lexer->pos, "Unterminated block comment."); 
     else if (c == '*' && lexer_look(lexer, 1) == '#') { 
      lexer_adv(lexer, 2); 
      depth--; 
     } else if (c == '#' && lexer_look(lexer, 1) == '*') { 
      lexer_adv(lexer, 2); 
      depth++; 
     } else 
      c = lexer_adv(lexer, 1); 
    } 
} 

static void lexer_comment(lexer_t* lexer) { 
    if (lexer_look(lexer, 1) == '*') 
     lexer_nested(lexer); 
    else { 
     char c; 
     while (((c = lexer_look(lexer, 0)) != '\n') && can_adv(lexer, 1)) 
      lexer_adv(lexer, 1); 
     new_line(lexer); 
    } 
} 

static token_t* lexer_str(lexer_t* lexer) { 
    size_t str_len = 0; 

    while (true) { 
     if (!can_adv(lexer, 1)) { 
      error_new(lexer->errors, lexer->len, lexer->pos, "Unterminated string."); 
      return NULL; 
     } 
     else if (lexer_look(lexer, 1) == '\"') { 
      lexer_adv(lexer, 2); 
      break; 
     } 
     else { 
      lexer_adv(lexer, 1); 
      str_len++; 
     } 
    } 

    char* string = malloc(str_len + 1); 
    for (size_t idx = 0; idx < str_len; idx++) 
     string[idx] = lexer->src[lexer->ptr - str_len + idx]; 
    string[str_len] = '\0'; 

    token_t* token = token_new(lexer, _str); 
    token->string = string; 
    return token; 
} 

static token_t* lexer_float(lexer_t* lexer, token_t* token, size_t v) { 
    size_t places = 0; 
    double d = v; 

    if (!isdigit(lexer_look(lexer, 1))) { return token; } 

    while (lexer->len > 0) { 
     char c = lexer_look(lexer, 1); 

     if (isdigit(c)) { 
      lexer_adv(lexer, 1); 
      d = (d * 10) + (c - '0'); 
      places++; 
     } else 
      break; 
    } 

    token->flt = d/(places * 10); 
    token->string = ""; 
    return token; 
} 

static token_t* lexer_num(lexer_t* lexer) { 
    token_t* token = token_new(lexer, _int); 
    size_t v = 0; 

    while (can_adv(lexer, 1)) { 
     char c = lexer_look(lexer, 0); 

     if (isdigit(c)) { 
      v = (v * 10) + (c - '0'); 
      lexer_adv(lexer, 1); 
     } else if (c == '.') { 
      lexer_adv(lexer, 1); 
      return lexer_float(lexer, token, v); 
     } else { 
      break; 
     } 
    } 

    token->integer = v; 
    token->string = ""; 
    return token; 
} 

static token_t* lexer_ident(lexer_t* lexer) { 
    token_t* token = token_new(lexer, _ident); 
    size_t id_len = 0; 

    while (can_adv(lexer, 1)) { 
     if (!isalpha(lexer_look(lexer, 0))) 
      break; 

     lexer_adv(lexer, 1); 
     id_len++; 
    } 

    char* ident = malloc(id_len + 1); 
    for (size_t idx = 0; idx < id_len; idx++) 
     ident[idx] = lexer->src[lexer->ptr - id_len + idx]; 
    ident[id_len] = '\0'; 

    token->string = ident; 
    return token; 
} 

static token_t* next_token(lexer_t* lexer) { 
    token_t* token = NULL; 

    while (token == NULL && can_adv(lexer, 1)) { 
     const int c = lexer_look(lexer, 0); 

     if (DEBUG) 
      printf("Current character: \"%c\", Length: %d, Pointer: %d \n", lexer_look(lexer, 0), lexer->len, lexer->ptr); 

     switch (c) { 
     case '=': 
      if (lexer_look(lexer, 1) == '=') { 
       token = token_new(lexer, _eqto); 
       lexer_adv(lexer, 2); 
       token->string = "=="; 
      } else { 
       token = token_new(lexer, _assign); 
       token->string = "="; 
       lexer_adv(lexer, 1); 
      } 

      break; 
     case '+': 
      if (lexer_look(lexer, 1) == '=') { 
       token = token_new(lexer, _addeql); 
       lexer_adv(lexer, 2); 
       token->string = "+="; 
      } else { 
       token = token_new(lexer, _add); 
       token->string = "+"; 
       lexer_adv(lexer, 1); 
      } 

      break; 
     case '-': 
      if (lexer_look(lexer, 1) == '=') { 
       token = token_new(lexer, _subeql); 
       lexer_adv(lexer, 2); 
       token->string = "-="; 
      } else { 
       token = token_new(lexer, _sub); 
       token->string = "-"; 
       lexer_adv(lexer, 1); 
      } 

      break; 
     case '*': 
      if (lexer_look(lexer, 1) == '=') { 
       token = token_new(lexer, _muleql); 
       lexer_adv(lexer, 2); 
       token->string = "*="; 
      } else { 
       token = token_new(lexer, _mul); 
       token->string = "*"; 
       lexer_adv(lexer, 1); 
      } 

      break; 
     case '/': 
      if (lexer_look(lexer, 1) == '=') { 
       token = token_new(lexer, _diveql); 
       lexer_adv(lexer, 2); 
       token->string = "/="; 
      } else { 
       token = token_new(lexer, _div); 
       token->string = "/"; 
       lexer_adv(lexer, 1); 
      } 

      break; 
     case '<': 
      if (lexer_look(lexer, 1) == '<') { 
       token = token_new(lexer, _nteq); 
       lexer_adv(lexer, 2); 
       token->string = "<="; 
      } else { 
       token = token_new(lexer, _bang); 
       token->string = "<"; 
       lexer_adv(lexer, 1); 
      } 

      break; 
     case '>': 
      if (lexer_look(lexer, 1) == '<') { 
       token = token_new(lexer, _nteq); 
       lexer_adv(lexer, 2); 
       token->string = ">="; 
      } 
      else { 
       token = token_new(lexer, _bang); 
       token->string = ">"; 
       lexer_adv(lexer, 1); 
      } 

      break; 
     case '&': 
      if (lexer_look(lexer, 1) == '&') { 
       token = token_new(lexer, _and); 
       lexer_adv(lexer, 2); 
       token->string = "&&"; 
      } else { 
       token = token_new(lexer, _notype); 
       lexer_adv(lexer, 1); 
      } 

      break; 
     case '|': 
      if (lexer_look(lexer, 1) == '|') { 
       token = token_new(lexer, _or); 
       lexer_adv(lexer, 2); 
       token->string = "||"; 
      } 
      else { 
       token = token_new(lexer, _notype); 
       lexer_adv(lexer, 1); 
      } 

      break; 
     case '%': 
      token = token_new(lexer, _mod); 
      token->string = "%"; 
      lexer_adv(lexer, 1); 
      break; 
     case '^': 
      token = token_new(lexer, _mod); 
      token->string = "^"; 
      lexer_adv(lexer, 1); 
      break; 
     case '!': 
      if (lexer_look(lexer, 1) == '=') { 
       token = token_new(lexer, _nteq); 
       lexer_adv(lexer, 2); 
       token->string = "!="; 
      } 
      else { 
       token = token_new(lexer, _bang); 
       token->string = "!"; 
       lexer_adv(lexer, 1); 
      } 

      break; 
     case '\"': 
      token = lexer_str(lexer); 
      break; 
     case '#': 
      lexer_comment(lexer); 
      break; 
     case '(': 
      token = token_new(lexer, _lpara); 
      token->string = "("; 
      lexer_adv(lexer, 1); 
      break; 
     case ')': 
      token = token_new(lexer, _rpara); 
      token->string = ")"; 
      lexer_adv(lexer, 1); 
      break; 
     case '{': 
      token = token_new(lexer, _lcurl); 
      token->string = "{"; 
      lexer_adv(lexer, 1); 
      break; 
     case '}': 
      token = token_new(lexer, _rcurl); 
      token->string = "}"; 
      lexer_adv(lexer, 1); 
      break; 
     case '[': 
      token = token_new(lexer, _lbrac); 
      token->string = "["; 
      lexer_adv(lexer, 1); 
      break; 
     case ']': 
      token = token_new(lexer, _rbrac); 
      token->string = "]"; 
      lexer_adv(lexer, 1); 
      break; 
     case ';': 
      token = token_new(lexer, _terml); 
      token->string = ";"; 
      lexer_adv(lexer, 1); 
      break; 
     default: 
      if (isalpha(c) || c == '_') 
       token = lexer_ident(lexer); 
      else if (isdigit(c) || c == '.') { 
       token = lexer_num(lexer); 
      } else if (isspace(c)) 
       lexer_adv(lexer, 1); 
      else 
       token = token_new(lexer, _eof); 

      break; 
     } 
    } 

    return token; 
} 

void lexer_print(lexer_t* lexer) { 
    size_t line = lexer->line; 
    size_t pos = lexer->pos; 
    size_t ptr = lexer->ptr; 
    token_t* token = next_token(lexer); 

    while (token != NULL && token->type != _eof) { 
     token_print(token); 
     token = next_token(lexer); 
    } 

    lexer->ptr = ptr; 
    lexer->pos = pos; 
} 

lexer_t* lexer_open(const char* file_name) { 
    FILE* file_ptr = fopen(file_name, "rb"); 
    lexer_t* lexer = malloc(sizeof(lexer_t)); 
    lexer->errors = errorlist_new(); 
    lexer->line = 1; 
    lexer->pos = 0; 
    lexer->ptr = 0; 

    if (file_ptr == NULL) { 
     error_new(lexer->errors, 0, 0, "Couldent open file \"%s\".\n", file_name); 
     fclose(file_ptr); 
     free(lexer); 
    } 

    if (fseek(file_ptr, 0, SEEK_END) != 0) { 
     fclose(file_ptr); 
     return NULL; 
    } 

    lexer->len = ftell(file_ptr); 
    if (lexer->len == -1) { 
     error_new(lexer->errors, 0, 0, "Unable to get the size of file \"%s\".\n", file_name); 
     fclose(file_ptr); 
     free(lexer); 
    } 
    fseek(file_ptr, 0, SEEK_SET); 

    lexer->src = malloc(lexer->len); 
    size_t r = fread(lexer->src, lexer->len, 1, file_ptr); 
    fclose(file_ptr); 
    return lexer; 
} 

void lexer_close(lexer_t* lexer) { 
    if (lexer->src != NULL) 
     free(lexer->src); 

    free(lexer); 
} 

헤더

#ifndef LEXER_H 
#define LEXER_H 

#include "error.h" 
#include <stdio.h> 
#include <stdbool.h> 
#include <malloc.h> 
#include <assert.h> 

typedef enum tk_type { 
    // primitives 
    _notype, 
    _str, 
    _gen_num, 
    _ident, 
    _type, 

    // symbols 
    _rbrac, 
    _lbrac, 
    _rpara, 
    _lpara, 
    _rcurl, 
    _lcurl, 
    _terml, 

    _assign, 
    _bang, 

    _add, 
    _addeql, 
    _sub, 
    _subeql, 
    _div, 
    _diveql, 
    _mul, 
    _muleql, 
    _exp, 
    _mod, 

    // comparison operators 
    _lt, 
    _lteq, 
    _gt, 
    _gteq, 
    _eqto, 
    _nteq, 
    _and, 
    _or, 

    // keywords 
    _while, 
    _for, 
    _if, 
    _else, 
    _match, 
    _case, 
    _return, 
    _break, 
    _int, 
    _float, 
    _enum, 
    _true, 
    _false, 
    _import, 
    _struct, 
    _mac, 
    _dbl, 
    _void, 
    _char, 
    _bool, 
    _const, 

    // abstract 
    _block, 
    _eof 
} tk_type; 

typedef struct token_t { 
    tk_type type; 
    size_t line; 
    size_t pos; 

    union { 
     char* string; 
     double flt; 
     size_t integer; 
    }; 
} token_t; 

typedef struct lexer_t { 
    size_t line; 
    size_t pos; 
    size_t ptr; 
    size_t len; 
    char* src; 

    errorlist_t* errors; 
} lexer_t; 

void lexer_print(lexer_t* lexer); 

#endif 

입력

int main() { 
    int var = 10 + 2; 
} 
+1

정보가 약간 희박합니다. 여러분의 의견 (혹시의 경우를 포함하여 hexdump 포함)은 무엇입니까?'token_t'는 어떻게 정의되고 어떻게 출력을 출력합니까? 이 오류는'can_adv()','lexer_look()','lexer_adv()','token_new()'에서 숨길 수 있습니다. 또한 :'lexer_t'는 어떻게 정의되고'lexer_num()'함수의 시작 부분에 그것들이 무엇입니까? 그리고 왜'v'의 데이터 타입이'size_t'입니까? – deamentiaemundi

+0

MCVE ([MCVE])를 만드는 방법을 검토하고 질문을 제공하여 질문을 제공하십시오. 현재 보여지는 코드에는 문제가 없다 (따라서 도시되지 않은 코드에 있음). 그러나 코드를 실행할 수 없으므로 쉽게 확신 할 수 없습니다. –

+0

이 코드에 오류가 있음을 보증 할 수 있지만 그 점을 살펴 보겠습니다. 감사합니다 – Hedron

답변

1

lexer_int에 명백한 문제가 마지막이 될 것 같다 :

token_tinteger, fltstring 필드를 오버레이 익명 조합을 포함하기 때문에
token->integer = v; 
token->string = ""; 

이 즉시 다음 읽기 수를 저장 "" 리터럴 정적 문자열에 대한 포인터를 덮어 씁니다. token->string = ""; 행을 삭제하려고합니다.

물론 token_print 루틴은 토큰이 문자열이 아니더라도 string 필드를 읽으려고하기 때문에 충돌 할 수 있습니다.

lexer_float은 동일한 문제가 있습니다 ...

+0

이것은 큰 도움입니다. 정말 고마워요. 수면을 제외하고는 현재 작동 중입니다.하지만 더 많은 수면을 취하면 해결할 수있는 또 다른 문제입니다. :) – Hedron