added parser file
This commit is contained in:
parent
8663a3c993
commit
e079f63d27
7 changed files with 154 additions and 134 deletions
6
makefile
6
makefile
|
|
@ -5,8 +5,8 @@ CC := clang -c -std=c17 -Wall -Wextra -pedantic -Werror
|
||||||
SRCS := $(shell find $(SRC) -name '*.c')
|
SRCS := $(shell find $(SRC) -name '*.c')
|
||||||
OBJS := $(SRCS:%=$(TARGET)/%.o)
|
OBJS := $(SRCS:%=$(TARGET)/%.o)
|
||||||
|
|
||||||
$(TARGET)/lox: $(TARGET)/lox.c.o $(TARGET)/scanner.c.o $(TARGET)/tokens.c.o $(TARGET)/utils.c.o
|
$(TARGET)/lox: $(TARGET)/lox.c.o $(TARGET)/parser.c.o $(TARGET)/scanner.c.o $(TARGET)/tokens.c.o $(TARGET)/utils.c.o
|
||||||
clang $(TARGET)/lox.c.o -L$(TARGET) -ltokens.c.o -lscanner.c.o -lutils.c.o -o $(TARGET)/lox
|
clang $(TARGET)/lox.c.o -L$(TARGET) -lparser.c.o -ltokens.c.o -lscanner.c.o -lutils.c.o -o $(TARGET)/lox
|
||||||
|
|
||||||
$(TARGET)/utils.c.o: $(SRC)/utils.c
|
$(TARGET)/utils.c.o: $(SRC)/utils.c
|
||||||
$(CC) $< -o $@
|
$(CC) $< -o $@
|
||||||
|
|
@ -17,6 +17,8 @@ $(TARGET)/tokens.c.o: $(SRC)/tokens.c
|
||||||
$(TARGET)/scanner.c.o: $(SRC)/scanner.c
|
$(TARGET)/scanner.c.o: $(SRC)/scanner.c
|
||||||
$(CC) $< -o $@
|
$(CC) $< -o $@
|
||||||
|
|
||||||
|
$(TARGET)/parser.c.o: $(SRC)/parser.c
|
||||||
|
$(CC) $< -o $@
|
||||||
|
|
||||||
$(TARGET)/lox.c.o: $(SRC)/lox.c $(TARGET)
|
$(TARGET)/lox.c.o: $(SRC)/lox.c $(TARGET)
|
||||||
$(CC) $< -o $@
|
$(CC) $< -o $@
|
||||||
|
|
|
||||||
131
src/lox.c
131
src/lox.c
|
|
@ -1,86 +1,83 @@
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include "scanner.h"
|
#include "scanner.h"
|
||||||
#include "tokens.h"
|
#include "tokens.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
int run_file(char* file);
|
int run_file(char *file);
|
||||||
void run_prompt(void);
|
void run_prompt(void);
|
||||||
ScanResult run(char* source);
|
ScanResult run(char *source);
|
||||||
|
|
||||||
int main(int argc, char* argv[]){
|
int main(int argc, char *argv[]) {
|
||||||
if (argc>2){
|
if (argc > 2) {
|
||||||
puts("Usage: lox [script]");
|
puts("Usage: lox [script]");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
} else if (argc == 2){
|
} else if (argc == 2) {
|
||||||
return run_file(argv[1]);
|
return run_file(argv[1]);
|
||||||
} else {
|
} else {
|
||||||
run_prompt();
|
run_prompt();
|
||||||
}
|
}
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int run_file(char* filename){
|
int run_file(char *filename) {
|
||||||
|
|
||||||
FILE* file = fopen(filename, "r");
|
FILE *file = fopen(filename, "r");
|
||||||
if (file == NULL){
|
if (file == NULL) {
|
||||||
printf("unable to open file '%s'\n", filename);
|
printf("unable to open file '%s'\n", filename);
|
||||||
return EXIT_FAILURE;
|
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;
|
||||||
}
|
}
|
||||||
char line[255];
|
strcat(content, line);
|
||||||
|
}
|
||||||
|
|
||||||
char* content = malloc(1);
|
fclose(file);
|
||||||
if (content == NULL){
|
|
||||||
puts("Out of memory");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
content[0] = '\0';
|
|
||||||
|
|
||||||
|
ScanResult scan_result = run(content);
|
||||||
|
|
||||||
while (fgets(line, sizeof(line), file)){
|
// FREE UP
|
||||||
content = realloc(content, strlen(content) + strlen(line) + 1 );
|
free(content);
|
||||||
if (content == NULL){
|
|
||||||
return EXIT_FAILURE;
|
if (scan_result.had_error) {
|
||||||
}
|
return 65;
|
||||||
strcat(content, line);
|
}
|
||||||
|
|
||||||
|
tokenlist_print(&scan_result.token_list);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void run_prompt(void) {
|
||||||
|
char line[255];
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
printf(">");
|
||||||
|
char *r = fgets(line, 255, stdin);
|
||||||
|
|
||||||
|
if (r == NULL) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(file);
|
int len = (int)strlen(line);
|
||||||
|
ScanResult scan_result = run(substring(line, 1, len - 1));
|
||||||
ScanResult scan_result = run(content);
|
|
||||||
|
|
||||||
// FREE UP
|
|
||||||
free(content);
|
|
||||||
|
|
||||||
if (scan_result.had_error){
|
|
||||||
return 65;
|
|
||||||
}
|
|
||||||
|
|
||||||
tokenlist_print(&scan_result.token_list);
|
tokenlist_print(&scan_result.token_list);
|
||||||
|
}
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void run_prompt(void){
|
ScanResult run(char *source) { return scan_tokens(source); }
|
||||||
char line[255];
|
|
||||||
|
|
||||||
for (;;){
|
|
||||||
printf(">");
|
|
||||||
char* r = fgets(line, 255, stdin);
|
|
||||||
|
|
||||||
if (r == NULL){
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
int len =(int)strlen(line);
|
|
||||||
ScanResult scan_result = run(substring(line, 1, len-1));
|
|
||||||
|
|
||||||
tokenlist_print(&scan_result.token_list);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ScanResult run(char* source){
|
|
||||||
return scan_tokens(source);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
21
src/parser.c
Normal file
21
src/parser.c
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
#include "parser.h"
|
||||||
|
#include "tokens.h"
|
||||||
|
|
||||||
|
enum ExprType {
|
||||||
|
Bin,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Binary {
|
||||||
|
Binary *left;
|
||||||
|
Token operator;
|
||||||
|
Binary *right;
|
||||||
|
};
|
||||||
|
|
||||||
|
union Expr {
|
||||||
|
Binary binary;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Expression {
|
||||||
|
enum ExprType type;
|
||||||
|
union Expr expr;
|
||||||
|
};
|
||||||
1
src/parser.h
Normal file
1
src/parser.h
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
typedef struct Binary Binary;
|
||||||
|
|
@ -6,46 +6,26 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
void scan_token(void);
|
static void scan_token(void);
|
||||||
void error(char *message);
|
static void error(char *message);
|
||||||
void report(char *where, char *message);
|
static void report(char *where, char *message);
|
||||||
bool is_at_end(void);
|
static bool is_at_end(void);
|
||||||
bool match(char expected);
|
static bool match(char expected);
|
||||||
char peek(void);
|
static char peek(void);
|
||||||
char peek_next(void);
|
static char peek_next(void);
|
||||||
void string(void);
|
static void string(void);
|
||||||
bool is_digit(char c);
|
static bool is_digit(char c);
|
||||||
void number(void);
|
static void number(void);
|
||||||
bool is_alpha(char c);
|
static bool is_alpha(char c);
|
||||||
bool is_alphanumeric(char c);
|
static bool is_alphanumeric(char c);
|
||||||
void identifier(void);
|
static void identifier(void);
|
||||||
|
|
||||||
bool had_error = false;
|
static bool had_error = false;
|
||||||
int current_pos = -1;
|
static int current_pos = -1;
|
||||||
int start = -1;
|
static int start = -1;
|
||||||
int current_line = -1;
|
static int current_line = -1;
|
||||||
char *source;
|
static char *source;
|
||||||
TokenList token_list;
|
static TokenList token_list;
|
||||||
|
|
||||||
static const enum TokenType *get_token(char *key) {
|
|
||||||
int low = 0;
|
|
||||||
int high = sizeof(keywords) / sizeof(Item);
|
|
||||||
|
|
||||||
while (low < high) {
|
|
||||||
int mid = (low + high) / 2;
|
|
||||||
|
|
||||||
int c = strcmp(keywords[mid].key, key);
|
|
||||||
if (c == 0) {
|
|
||||||
return &keywords[mid].value;
|
|
||||||
}
|
|
||||||
if (c < 0) {
|
|
||||||
low = mid + 1;
|
|
||||||
} else {
|
|
||||||
high = mid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ScanResult scan_tokens(char *src) {
|
ScanResult scan_tokens(char *src) {
|
||||||
current_pos = 0;
|
current_pos = 0;
|
||||||
|
|
@ -70,7 +50,7 @@ ScanResult scan_tokens(char *src) {
|
||||||
return scan_result;
|
return scan_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_token(enum TokenType type) {
|
static void add_token(TokenType type) {
|
||||||
Token token;
|
Token token;
|
||||||
token.type = type;
|
token.type = type;
|
||||||
token.lexeme = substring(source, start, current_pos);
|
token.lexeme = substring(source, start, current_pos);
|
||||||
|
|
@ -80,7 +60,7 @@ void add_token(enum TokenType type) {
|
||||||
tokenlist_add(&token_list, token);
|
tokenlist_add(&token_list, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_token_with_literal(enum TokenType type, char *literal) {
|
static void add_token_with_literal(TokenType type, char *literal) {
|
||||||
Token token;
|
Token token;
|
||||||
token.type = type;
|
token.type = type;
|
||||||
token.lexeme = substring(source, start, current_pos);
|
token.lexeme = substring(source, start, current_pos);
|
||||||
|
|
@ -90,12 +70,12 @@ void add_token_with_literal(enum TokenType type, char *literal) {
|
||||||
tokenlist_add(&token_list, token);
|
tokenlist_add(&token_list, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
char advance(void) {
|
static char advance(void) {
|
||||||
char c = source[current_pos++];
|
char c = source[current_pos++];
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
void scan_token(void) {
|
static void scan_token(void) {
|
||||||
char c = advance();
|
char c = advance();
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
|
@ -166,14 +146,14 @@ void scan_token(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void identifier(void) {
|
static void identifier(void) {
|
||||||
while (is_alphanumeric(peek())) {
|
while (is_alphanumeric(peek())) {
|
||||||
advance();
|
advance();
|
||||||
}
|
}
|
||||||
|
|
||||||
char *text = substring(source, start + 1, current_pos - start);
|
char *text = substring(source, start + 1, current_pos - start);
|
||||||
|
|
||||||
const enum TokenType *tokentype = get_token(text);
|
const TokenType *tokentype = get_keyword_token(text);
|
||||||
if (tokentype == NULL) {
|
if (tokentype == NULL) {
|
||||||
add_token(IDENTIFIER);
|
add_token(IDENTIFIER);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -181,7 +161,7 @@ void identifier(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void number(void) {
|
static void number(void) {
|
||||||
while (is_digit(peek()))
|
while (is_digit(peek()))
|
||||||
advance();
|
advance();
|
||||||
if (peek() == '.' && is_digit((peek_next())))
|
if (peek() == '.' && is_digit((peek_next())))
|
||||||
|
|
@ -212,7 +192,7 @@ void string(void) {
|
||||||
add_token_with_literal(STRING, string);
|
add_token_with_literal(STRING, string);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool match(char expected) {
|
static bool match(char expected) {
|
||||||
if (is_at_end()) {
|
if (is_at_end()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -223,30 +203,30 @@ bool match(char expected) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
char peek_next(void) {
|
static char peek_next(void) {
|
||||||
if (current_pos + 1 >= (int)strlen(source)) {
|
if (current_pos + 1 >= (int)strlen(source)) {
|
||||||
return '\0';
|
return '\0';
|
||||||
}
|
}
|
||||||
return source[current_pos + 1];
|
return source[current_pos + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
char peek(void) {
|
static char peek(void) {
|
||||||
if (is_at_end()) {
|
if (is_at_end()) {
|
||||||
return '\0';
|
return '\0';
|
||||||
}
|
}
|
||||||
return source[current_pos];
|
return source[current_pos];
|
||||||
}
|
}
|
||||||
bool is_alpha(char c) {
|
static bool is_alpha(char c) {
|
||||||
return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_');
|
return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_');
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_alphanumeric(char c) { return is_alpha(c) || is_digit(c); }
|
static bool is_alphanumeric(char c) { return is_alpha(c) || is_digit(c); }
|
||||||
|
|
||||||
bool is_at_end(void) { return current_pos >= (int)strlen(source); }
|
static bool is_at_end(void) { return current_pos >= (int)strlen(source); }
|
||||||
|
|
||||||
void error(char *message) { report("", message); }
|
static void error(char *message) { report("", message); }
|
||||||
|
|
||||||
void report(char *where, char *message) {
|
static void report(char *where, char *message) {
|
||||||
printf("*[Line %i] Error %s : %s\n", current_line, where, message);
|
printf("*[Line %i] Error %s : %s\n", current_line, where, message);
|
||||||
had_error = true;
|
had_error = true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ ScanResult scan_tokens(char *source);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *key;
|
const char *key;
|
||||||
const enum TokenType value;
|
const TokenType value;
|
||||||
} Item;
|
} Item;
|
||||||
|
|
||||||
static const Item keywords[] = {
|
static const Item keywords[] = {
|
||||||
|
|
@ -23,4 +23,23 @@ static const Item keywords[] = {
|
||||||
{"or", OR}, {"print", PRINT}, {"return", RETURN}, {"super", SUPER},
|
{"or", OR}, {"print", PRINT}, {"return", RETURN}, {"super", SUPER},
|
||||||
{"this", THIS}, {"true", TRUE}, {"var", VAR}, {"while", WHILE}};
|
{"this", THIS}, {"true", TRUE}, {"var", VAR}, {"while", WHILE}};
|
||||||
|
|
||||||
|
inline static const TokenType *get_keyword_token(char *key) {
|
||||||
|
int low = 0;
|
||||||
|
int high = sizeof(keywords) / sizeof(Item);
|
||||||
|
|
||||||
|
while (low < high) {
|
||||||
|
int mid = (low + high) / 2;
|
||||||
|
|
||||||
|
int c = strcmp(keywords[mid].key, key);
|
||||||
|
if (c == 0) {
|
||||||
|
return &keywords[mid].value;
|
||||||
|
}
|
||||||
|
if (c < 0) {
|
||||||
|
low = mid + 1;
|
||||||
|
} else {
|
||||||
|
high = mid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
20
src/tokens.h
20
src/tokens.h
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef TOKENS_H
|
#ifndef TOKENS_H
|
||||||
#define TOKENS_H
|
#define TOKENS_H
|
||||||
|
|
||||||
enum TokenType {
|
typedef enum {
|
||||||
LEFT_PAREN,
|
LEFT_PAREN,
|
||||||
RIGHT_PAREN,
|
RIGHT_PAREN,
|
||||||
LEFT_BRACE,
|
LEFT_BRACE,
|
||||||
|
|
@ -41,16 +41,9 @@ enum TokenType {
|
||||||
VAR,
|
VAR,
|
||||||
WHILE,
|
WHILE,
|
||||||
END_OF_FILE
|
END_OF_FILE
|
||||||
};
|
} TokenType;
|
||||||
|
|
||||||
typedef struct {
|
static inline const char *token_name(TokenType type) {
|
||||||
enum TokenType type;
|
|
||||||
char *lexeme;
|
|
||||||
void *literal;
|
|
||||||
int line;
|
|
||||||
} Token;
|
|
||||||
|
|
||||||
static inline const char *token_name(enum TokenType type) {
|
|
||||||
static const char *tokens[] = {
|
static const char *tokens[] = {
|
||||||
"LEFT_PAREN", "RIGHT_PAREN", "LEFT_BRACE", "RIGHT_BRACE", "COMMA",
|
"LEFT_PAREN", "RIGHT_PAREN", "LEFT_BRACE", "RIGHT_BRACE", "COMMA",
|
||||||
"DOT", "MINUS", "PLUS", "SEMICOLON", "SLASH",
|
"DOT", "MINUS", "PLUS", "SEMICOLON", "SLASH",
|
||||||
|
|
@ -65,6 +58,13 @@ static inline const char *token_name(enum TokenType type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
TokenType type;
|
||||||
|
char *lexeme;
|
||||||
|
void *literal;
|
||||||
|
int line;
|
||||||
|
} Token;
|
||||||
|
|
||||||
|
typedef struct TokenList {
|
||||||
Token *tokens;
|
Token *tokens;
|
||||||
int size;
|
int size;
|
||||||
int capacity;
|
int capacity;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue