more smaller sources, another page in the book
This commit is contained in:
parent
7f670a5301
commit
6e84fea3d1
6 changed files with 185 additions and 92 deletions
11
makefile
11
makefile
|
|
@ -5,12 +5,19 @@ 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)/tokens.c.o
|
$(TARGET)/lox: $(TARGET)/lox.c.o $(TARGET)/scanner.c.o $(TARGET)/tokens.c.o $(TARGET)/utils.c.o
|
||||||
clang $(TARGET)/lox.c.o -L$(TARGET) -ltokens.c.o -o $(TARGET)/lox
|
clang $(TARGET)/lox.c.o -L$(TARGET) -ltokens.c.o -lscanner.c.o -lutils.c.o -o $(TARGET)/lox
|
||||||
|
|
||||||
|
$(TARGET)/utils.c.o: $(SRC)/utils.c
|
||||||
|
$(CC) $< -o $@
|
||||||
|
|
||||||
$(TARGET)/tokens.c.o: $(SRC)/tokens.c
|
$(TARGET)/tokens.c.o: $(SRC)/tokens.c
|
||||||
$(CC) $< -o $@
|
$(CC) $< -o $@
|
||||||
|
|
||||||
|
$(TARGET)/scanner.c.o: $(SRC)/scanner.c
|
||||||
|
$(CC) $< -o $@
|
||||||
|
|
||||||
|
|
||||||
$(TARGET)/lox.c.o: $(SRC)/lox.c $(TARGET)
|
$(TARGET)/lox.c.o: $(SRC)/lox.c $(TARGET)
|
||||||
$(CC) $< -o $@
|
$(CC) $< -o $@
|
||||||
|
|
||||||
|
|
|
||||||
103
src/lox.c
103
src/lox.c
|
|
@ -2,18 +2,13 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include "scanner.h"
|
||||||
#include "tokens.h"
|
#include "tokens.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
int run_file(char* file);
|
int run_file(char* file);
|
||||||
void run_prompt(void);
|
void run_prompt(void);
|
||||||
void run(char* source);
|
ScanResult 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[]){
|
int main(int argc, char* argv[]){
|
||||||
if (argc>2){
|
if (argc>2){
|
||||||
|
|
@ -27,8 +22,8 @@ int main(int argc, char* argv[]){
|
||||||
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);
|
||||||
|
|
@ -54,15 +49,17 @@ int run_file(char* filename){
|
||||||
|
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
|
||||||
run(content);
|
ScanResult scan_result = run(content);
|
||||||
|
|
||||||
// FREE UP
|
// FREE UP
|
||||||
free(content);
|
free(content);
|
||||||
|
|
||||||
if (had_error){
|
if (scan_result.had_error){
|
||||||
return 65;
|
return 65;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tokenlist_print(&scan_result.token_list);
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -78,86 +75,12 @@ void run_prompt(void){
|
||||||
}
|
}
|
||||||
|
|
||||||
int len =(int)strlen(line);
|
int len =(int)strlen(line);
|
||||||
run(substring(line, 1, len-1));
|
ScanResult scan_result = run(substring(line, 1, len-1));
|
||||||
had_error = false;
|
|
||||||
|
tokenlist_print(&scan_result.token_list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void run(char* source){
|
ScanResult run(char* source){
|
||||||
scan_tokens(source);
|
return scan_tokens(source);
|
||||||
}
|
|
||||||
|
|
||||||
void scan_tokens(char* source){
|
|
||||||
int current = 0;
|
|
||||||
int start = 0;
|
|
||||||
int line = 1;
|
|
||||||
|
|
||||||
TokenList token_list;
|
|
||||||
tokenlist_init(&token_list);
|
|
||||||
int len = (int)strlen(source);
|
|
||||||
|
|
||||||
while (current < len) {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
char advance(char * source, int* pos){
|
|
||||||
char c = source[*pos];
|
|
||||||
(*pos) +=1;
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
void scan_token(char* source, int line, int start, int* current_pos, TokenList* token_list){
|
|
||||||
char c = advance(source, current_pos);
|
|
||||||
|
|
||||||
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, MINUS, start, *current_pos); break;
|
|
||||||
|
|
||||||
default: error(line, "Unexpected character."); 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+=1){
|
|
||||||
*(ptr+c) = *(string+position-1);
|
|
||||||
string += sizeof(char);
|
|
||||||
}
|
|
||||||
*(ptr+c) = '\0';
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
124
src/scanner.c
Normal file
124
src/scanner.c
Normal file
|
|
@ -0,0 +1,124 @@
|
||||||
|
#include "scanner.h"
|
||||||
|
#include "tokens.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
void scan_token(void);
|
||||||
|
void error(char *message);
|
||||||
|
void report(char *where, char *message);
|
||||||
|
bool is_at_end(void);
|
||||||
|
bool match(char expected);
|
||||||
|
|
||||||
|
bool had_error = false;
|
||||||
|
int current_pos = -1;
|
||||||
|
int start = -1;
|
||||||
|
int current_line = -1;
|
||||||
|
char *source;
|
||||||
|
TokenList token_list;
|
||||||
|
|
||||||
|
ScanResult scan_tokens(char *src) {
|
||||||
|
current_pos = 0;
|
||||||
|
start = 0;
|
||||||
|
current_line = 1;
|
||||||
|
source = src;
|
||||||
|
|
||||||
|
tokenlist_init(&token_list);
|
||||||
|
int len = (int)strlen(source);
|
||||||
|
|
||||||
|
while (current_pos < len) {
|
||||||
|
start = current_pos;
|
||||||
|
scan_token();
|
||||||
|
}
|
||||||
|
|
||||||
|
ScanResult scan_result;
|
||||||
|
scan_result.token_list = token_list;
|
||||||
|
scan_result.had_error = had_error;
|
||||||
|
|
||||||
|
// tokenlist_print(&scan_result.token_list);
|
||||||
|
|
||||||
|
return scan_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_token(enum TokenType type) {
|
||||||
|
Token token;
|
||||||
|
token.type = type;
|
||||||
|
token.lexeme = substring(source, start, current_pos);
|
||||||
|
token.literal = NULL;
|
||||||
|
token.line = current_line;
|
||||||
|
|
||||||
|
tokenlist_add(&token_list, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
char advance(void) {
|
||||||
|
char c = source[current_pos++];
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
void scan_token(void) {
|
||||||
|
char c = advance();
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case '(':
|
||||||
|
add_token(LEFT_PAREN);
|
||||||
|
break;
|
||||||
|
case ')':
|
||||||
|
add_token(RIGHT_PAREN);
|
||||||
|
break;
|
||||||
|
case '{':
|
||||||
|
add_token(LEFT_BRACE);
|
||||||
|
break;
|
||||||
|
case '}':
|
||||||
|
add_token(RIGHT_BRACE);
|
||||||
|
break;
|
||||||
|
case ',':
|
||||||
|
add_token(COMMA);
|
||||||
|
break;
|
||||||
|
case '.':
|
||||||
|
add_token(DOT);
|
||||||
|
break;
|
||||||
|
case '+':
|
||||||
|
add_token(PLUS);
|
||||||
|
break;
|
||||||
|
case '-':
|
||||||
|
add_token(MINUS);
|
||||||
|
break;
|
||||||
|
case '!':
|
||||||
|
add_token(match('=') ? BANG_EQUAL : BANG);
|
||||||
|
break;
|
||||||
|
case '=':
|
||||||
|
add_token(match('=') ? EQUAL_EQUAL : EQUAL);
|
||||||
|
break;
|
||||||
|
case '>':
|
||||||
|
add_token(match('=') ? GREATER_EQUAL : GREATER);
|
||||||
|
break;
|
||||||
|
case '<':
|
||||||
|
add_token(match('=') ? LESS_EQUAL : LESS);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error("Unexpected character.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool match(char expected) {
|
||||||
|
if (is_at_end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (expected != source[current_pos]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
current_pos += 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_at_end(void) { return current_pos >= (int)strlen(source); }
|
||||||
|
|
||||||
|
void error(char *message) { report("", message); }
|
||||||
|
|
||||||
|
void report(char *where, char *message) {
|
||||||
|
printf("*[Line %i] Error %s : %s\n", current_line, where, message);
|
||||||
|
had_error = true;
|
||||||
|
}
|
||||||
14
src/scanner.h
Normal file
14
src/scanner.h
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
#ifndef SCANNER_H
|
||||||
|
#define SCANNER_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "tokens.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool had_error;
|
||||||
|
TokenList token_list;
|
||||||
|
} ScanResult;
|
||||||
|
|
||||||
|
ScanResult scan_tokens(char* source);
|
||||||
|
|
||||||
|
#endif
|
||||||
19
src/utils.c
Normal file
19
src/utils.c
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
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+=1){
|
||||||
|
*(ptr+c) = *(string+position-1);
|
||||||
|
string += sizeof(char);
|
||||||
|
}
|
||||||
|
*(ptr+c) = '\0';
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
6
src/utils.h
Normal file
6
src/utils.h
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
#ifndef UTILS_H
|
||||||
|
#define UTILS_H
|
||||||
|
|
||||||
|
char* substring(char* string, int position, int length);
|
||||||
|
|
||||||
|
#endif
|
||||||
Loading…
Add table
Reference in a new issue