#include "types.h" #include #include #include #include typedef struct Token { // identifying tag enum TokenType { t_error, t_size, t_multiply, t_divide, t_add, t_subtract, t_whitespace, t_newline, t_number, } type; // change to offset + size, or line + col -- alleviated by helper structure of // ptrs to each newline union Data { i32 number; } data; } Token_t; // Should also add helper structure with pointers to each line static isize f_read(FILE* stream, char** dst); static i64 f_size(FILE* stream); static void l_print_token(Token_t token); static Token_t* l_read(char* text, isize text_length, Token_t* dst); int main(int argc, char* argv[]) { if (argc == 2) { FILE* f = NULL; char* contents = NULL; isize content_length = -1; Token_t* tokens = NULL; f = fopen(argv[1], "r"); if (f == NULL) { fprintf(stdout, "! Failed to open file: %s\n", argv[1]); } if (f != NULL) { content_length = f_read(f, &contents); if (content_length > 0) { printf("%s:%ld\n%s\n", argv[1], content_length, contents); } fclose(f); } if (content_length > 0) { tokens = l_read(contents, strlen(contents), NULL); free(contents); } if (tokens != NULL) { printf("%d tokens\n", tokens[0].data.number); for (int t = 0; t < tokens[0].data.number; t++) { l_print_token(tokens[t]); } } } return 0; } /* Copies the contents of the file stream to *dst. * @param stream An open file stream. * @param dst** Destination buffer. If *dst is NULL allocates a buffer the size * of stream using malloc. * @return The number of bytes copied into dst. * @error returns -1 on error. */ static isize f_read(FILE* stream, char** dst) { i64 file_sz = f_size(stream); if (dst == NULL) { fprintf(stderr, "! Got NULL ptr\n"); } if (dst != NULL && *dst == NULL && file_sz > 0) { *dst = (char*)malloc(file_sz * sizeof(char)); } if (dst != NULL && *dst == NULL && file_sz > 0) { fprintf(stderr, "! Failed to allocate %ld bytes\n", file_sz * sizeof(char)); } isize bytes_read = -1; if (dst != NULL && *dst != NULL && file_sz > 0) { bytes_read = fread(*dst, sizeof(char), file_sz, stream); } if (bytes_read < file_sz) { fprintf(stderr, "! Failed to read file, read %ld out of %ld bytes\n", bytes_read, file_sz); } return bytes_read; } /* Returns the size in bytes and rewinds the stream. * @param stream An open file stream. * @return the size of the file in bytes. * @error Returns -1 on error. */ static i64 f_size(FILE* stream) { // Could ftell and rewind to previous position, but scratch that i64 size = -1; i32 error = fseek(stream, 0, SEEK_END); if (error) { // TODO: handle pipes (check errno == ESPIPE) fprintf(stderr, "! Failed to seek file: %s\n", strerror(errno)); } else { size = ftell(stream); rewind(stream); } return size; } static void l_print_token(Token_t token) { switch (token.type) { case t_error: fputs(" error ", stdout); break; case t_size: printf(" [%d] ", token.data.number); break; case t_multiply: fputs(" * ", stdout); break; case t_divide: fputs(" / ", stdout); break; case t_add: fputs(" + ", stdout); break; case t_subtract: fputs(" - ", stdout); break; case t_number: printf("%d", token.data.number); break; default: break; } } /* Reads text and parses it into an array of tokens * @param text A buffer holding the input text * @return a pointer to dst * @error Returns NULL on error. */ static Token_t* l_read(char* text, isize text_length, Token_t* dst) { if (text_length > 0 && dst == NULL) { dst = (Token_t*)malloc(text_length * sizeof(Token_t)); } if (text_length > 0 && dst == NULL) { fprintf(stderr, "! Failed to allocate %ld bytes\n", text_length * sizeof(Token_t)); } if (text_length > 0 && dst != NULL) { isize i = 0; isize t = 1; i32 error = 0; dst[0].type = t_size; dst[0].data.number = 0; // TODO: rewrite to // if token != last-token // dst = token,line,col // last-token = token // t++; // while (last-token != error) do { switch (text[i]) { // case t_size: // break; case '*': dst[t].type = t_multiply; t++; break; case '/': dst[t].type = t_divide; t++; break; case t_add: dst[t].type = t_add; t++; break; case '-': dst[t].type = t_subtract; t++; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': dst[t].type = t_number; dst[t].data.number = text[i] - '0'; t++; break; case '+': dst[t].type = t_add; t++; break; case ' ': case '\t': dst[t].type = t_whitespace; t++; break; case '\n': dst[t].type = t_newline; t++; break; default: dst[t].type = t_error; t++; error = 1; break; } i++; } while (!error && i < text_length); dst[0].data.number = t; } return dst; }