WIP
This commit is contained in:
commit
c497732cb5
5 changed files with 300 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
target/
|
||||
20
makefile
Normal file
20
makefile
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
TARGET := ./target
|
||||
SRC := ./src
|
||||
CC := clang -c -std=c17 -Wall -Wextra -pedantic -Werror
|
||||
|
||||
SRCS := $(shell find $(SRC) -name '*.c')
|
||||
OBJS := $(SRCS:%=$(TARGET)/%.o)
|
||||
|
||||
#$(TARGET)/lox: $(OBJS)
|
||||
# clang $(TARGET)/lox.o -L$(TARGET) -ltokens.o -o $(TARGET)/lox
|
||||
|
||||
|
||||
$(TARGET)/%.c.o: $(SRC)/%.c $(TARGET)
|
||||
$(CC) $< -o $@
|
||||
|
||||
$(TARGET):
|
||||
mkdir -p $(TARGET)
|
||||
|
||||
clean:
|
||||
rm -r $(TARGET)/*
|
||||
|
||||
156
src/lox.c
Normal file
156
src/lox.c
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include "tokens.h"
|
||||
|
||||
int run_file(char* file);
|
||||
void run_prompt(void);
|
||||
void run(char* source);
|
||||
void scan_tokens(char* source);
|
||||
void scan_token(char* source, int line, int start, int* current_pos, TokenList* token_list);
|
||||
void error(int line, char* nessage);
|
||||
void report(int line, char* where, char* message);
|
||||
char* substring(char* string, int position, int length);
|
||||
|
||||
static bool had_error = false;
|
||||
|
||||
int main(int argc, char* argv[]){
|
||||
if (argc>2){
|
||||
puts("Usage: lox [script]");
|
||||
return EXIT_FAILURE;
|
||||
} else if (argc == 2){
|
||||
return run_file(argv[1]);
|
||||
} else {
|
||||
run_prompt();
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int run_file(char* filename){
|
||||
FILE* file = fopen(filename, "r");
|
||||
if (file == NULL){
|
||||
printf("unable to open file '%s'\n", filename);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
char line[255];
|
||||
|
||||
char* content = malloc(1);
|
||||
if (content == NULL){
|
||||
puts("Out of memory");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
content[0] = '\0';
|
||||
|
||||
|
||||
while (fgets(line, sizeof(line), file)){
|
||||
content = realloc(content, strlen(content) + strlen(line) + 1 );
|
||||
if (content == NULL){
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
strcat(content, line);
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
run(content);
|
||||
|
||||
// FREE UP
|
||||
free(content);
|
||||
|
||||
if (had_error){
|
||||
return 65;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void run_prompt(void){
|
||||
char line[255];
|
||||
|
||||
for (;;){
|
||||
printf(">");
|
||||
char* r = fgets(line, 255, stdin);
|
||||
|
||||
if (r == NULL){
|
||||
break;
|
||||
}
|
||||
|
||||
run(line);
|
||||
had_error = false;
|
||||
}
|
||||
}
|
||||
|
||||
void run(char* source){
|
||||
printf("%s", source);
|
||||
scan_tokens(source);
|
||||
}
|
||||
|
||||
void scan_tokens(char* source){
|
||||
int current = 0;
|
||||
int start = 0;
|
||||
int line = 1;
|
||||
|
||||
TokenList token_list;
|
||||
tokenlist_init(&token_list);
|
||||
|
||||
while (current < (int)strlen(source)) {
|
||||
start = current;
|
||||
scan_token(source, line, start, ¤t, &token_list);
|
||||
}
|
||||
tokenlist_print(&token_list);
|
||||
}
|
||||
|
||||
void add_token(char* source, int line, TokenList* token_list, enum TokenType type, int start, int current_pos){
|
||||
Token token;
|
||||
token.type = type;
|
||||
token.lexeme = substring(source, start, current_pos);
|
||||
token.literal = NULL;
|
||||
token.line = line;
|
||||
|
||||
tokenlist_add(token_list, token);
|
||||
}
|
||||
|
||||
void scan_token(char* source, int line, int start, int* current_pos, TokenList* token_list){
|
||||
char c = source[*current_pos];
|
||||
(*current_pos) += 1;
|
||||
switch (c){
|
||||
case '(': add_token(source, line, token_list, LEFT_PAREN, start, *current_pos); break;
|
||||
case ')': add_token(source, line, token_list, RIGHT_PAREN, start, *current_pos); break;
|
||||
case '{': add_token(source, line, token_list, LEFT_BRACE, start, *current_pos); break;
|
||||
case '}': add_token(source, line, token_list, RIGHT_BRACE, start, *current_pos); break;
|
||||
case ',': add_token(source, line, token_list, COMMA, start, *current_pos); break;
|
||||
case '.': add_token(source, line, token_list, DOT, start, *current_pos); break;
|
||||
case '+': add_token(source, line, token_list, PLUS, start, *current_pos); break;
|
||||
case ';': add_token(source, line, token_list, SEMICOLON, start, *current_pos); break;
|
||||
case '/': add_token(source, line, token_list, SLASH, start, *current_pos); break;
|
||||
}
|
||||
}
|
||||
|
||||
void error(int line, char* message){
|
||||
report(line, "", message);
|
||||
}
|
||||
|
||||
void report(int line, char* where, char* message){
|
||||
printf("[Line %i] Error %s : %s\n", line, where, message);
|
||||
had_error = true;
|
||||
}
|
||||
|
||||
char* substring(char* string, int position, int length){
|
||||
char* ptr = malloc(length+1);
|
||||
if (ptr == NULL) {
|
||||
printf("out of memory");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int c;
|
||||
for (c=0; c< length; c++){
|
||||
*(ptr+c) = *(string+position-1);
|
||||
string += sizeof(char);
|
||||
}
|
||||
*(ptr+c) = '\0';
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
83
src/tokens.c
Normal file
83
src/tokens.c
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "tokens.h"
|
||||
|
||||
char* token_name(Token* token){
|
||||
char* type;
|
||||
switch (token->type){
|
||||
case LEFT_PAREN: type = "LEFT_PAREN"; break;
|
||||
case RIGHT_PAREN: type = "RIGHT_PAREN"; break;
|
||||
case LEFT_BRACE: type = "LEFT_BRACE"; break;
|
||||
case RIGHT_BRACE: type = "RIGHT_BRACE"; break;
|
||||
case COMMA: type = "COMMA"; break;
|
||||
case DOT: type = "DOT"; break;
|
||||
case MINUS: type = "MINUS"; break;
|
||||
case PLUS: type = "PLUS"; break;
|
||||
case SEMICOLON: type = "SEMICOLON"; break;
|
||||
case SLASH: type = "SLASH"; break;
|
||||
case STAR: type = "STAR"; break;
|
||||
case BANG: type = "BANG"; break;
|
||||
case BANG_EQUAL: type = "BANG_EQUAL"; break;
|
||||
case EQUAL: type = "EQUAL"; break;
|
||||
case EQUAL_EQUAL: type = "EQUAL_EQUAL"; break;
|
||||
case GREATER: type = "GREATER"; break;
|
||||
case GREATER_EQUAL: type = "GREATER_EQUAL"; break;
|
||||
case LESS: type = "LESS"; break;
|
||||
case LESS_EQUAL: type = "LESS_EQUAL"; break;
|
||||
case IDENTIFIER: type = "IDENTIFIER"; break;
|
||||
case STRING: type = "STRING"; break;
|
||||
case NUMBER: type = "NUMBER"; break;
|
||||
case AND: type = "AND"; break;
|
||||
case CLASS: type = "CLASS"; break;
|
||||
case ELSE: type = "ELSE"; break;
|
||||
case FALSE: type = "FALSE"; break;
|
||||
case FUN: type = "FUN"; break;
|
||||
case FOR: type = "FOR"; break;
|
||||
case IF: type = "IF"; break;
|
||||
case NIL: type = "NIL"; break;
|
||||
case OR: type = "OR"; break;
|
||||
case PRINT: type = "PRINT"; break;
|
||||
case RETURN: type = "RETURN"; break;
|
||||
case SUPER: type = "SUPER"; break;
|
||||
case THIS: type = "THIS"; break;
|
||||
case TRUE: type = "TRUE"; break;
|
||||
case VAR: type = "VAR"; break;
|
||||
case WHILE: type = "WHILE"; break;
|
||||
case END_OF_FILE: type = "EOF"; break;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
void tokenlist_init(TokenList* list){
|
||||
list->tokens = malloc(sizeof(Token) * 32);
|
||||
list->size = 0;
|
||||
list->capacity = 32;
|
||||
}
|
||||
|
||||
void tokenlist_add(TokenList* list, Token value){
|
||||
if (list->size >= list->capacity){
|
||||
list->capacity *= 2;
|
||||
list->tokens = realloc(list->tokens, sizeof(Token)* list->capacity);
|
||||
}
|
||||
list->tokens[list->size] = value;
|
||||
list->size +=1;
|
||||
}
|
||||
|
||||
Token* tokenlist_get(TokenList* list, int index){
|
||||
if (index >= list->size || index < 0){
|
||||
printf("Index %d out of bounds for list of size %d\n", index, list->size);
|
||||
exit(1);
|
||||
}
|
||||
return &list->tokens[index];
|
||||
}
|
||||
|
||||
void tokenlist_print(TokenList* tokenlist){
|
||||
for (int i=0; i< tokenlist->size; i++){
|
||||
printf("%s, ", token_name(tokenlist_get(tokenlist, i)));
|
||||
}
|
||||
}
|
||||
|
||||
void tokenlist_free(TokenList* list){
|
||||
free(list->tokens);
|
||||
}
|
||||
|
||||
40
src/tokens.h
Normal file
40
src/tokens.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#ifndef TOKENS_H
|
||||
#define TOKENS_H
|
||||
|
||||
enum TokenType{
|
||||
LEFT_PAREN, RIGHT_PAREN, LEFT_BRACE, RIGHT_BRACE,
|
||||
COMMA, DOT, MINUS, PLUS, SEMICOLON, SLASH, STAR,
|
||||
BANG, BANG_EQUAL, EQUAL, EQUAL_EQUAL,
|
||||
GREATER, GREATER_EQUAL, LESS, LESS_EQUAL,
|
||||
IDENTIFIER, STRING, NUMBER,
|
||||
AND, CLASS, ELSE, FALSE, FUN, FOR, IF, NIL, OR,
|
||||
PRINT, RETURN, SUPER, THIS, TRUE, VAR, WHILE,
|
||||
END_OF_FILE
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
enum TokenType type;
|
||||
char* lexeme;
|
||||
void* literal;
|
||||
int line;
|
||||
} Token;
|
||||
|
||||
char* token_name(Token* token);
|
||||
|
||||
typedef struct {
|
||||
Token* tokens;
|
||||
int size;
|
||||
int capacity;
|
||||
} TokenList;
|
||||
|
||||
void tokenlist_init(TokenList* list);
|
||||
|
||||
void tokenlist_add(TokenList* list, Token value);
|
||||
|
||||
Token* tokenlist_get(TokenList* list, int index);
|
||||
|
||||
void tokenlist_print(TokenList* tokenlist);
|
||||
|
||||
void tokenlist_free(TokenList* list);
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Reference in a new issue