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')
|
||||
OBJS := $(SRCS:%=$(TARGET)/%.o)
|
||||
|
||||
$(TARGET)/lox: $(TARGET)/lox.c.o $(TARGET)/tokens.c.o
|
||||
clang $(TARGET)/lox.c.o -L$(TARGET) -ltokens.c.o -o $(TARGET)/lox
|
||||
$(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 -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
|
||||
$(CC) $< -o $@
|
||||
|
||||
$(TARGET)/scanner.c.o: $(SRC)/scanner.c
|
||||
$(CC) $< -o $@
|
||||
|
||||
|
||||
$(TARGET)/lox.c.o: $(SRC)/lox.c $(TARGET)
|
||||
$(CC) $< -o $@
|
||||
|
||||
|
|
|
|||
103
src/lox.c
103
src/lox.c
|
|
@ -2,18 +2,13 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include "scanner.h"
|
||||
#include "tokens.h"
|
||||
#include "utils.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;
|
||||
ScanResult run(char* source);
|
||||
|
||||
int main(int argc, char* argv[]){
|
||||
if (argc>2){
|
||||
|
|
@ -27,8 +22,8 @@ int main(int argc, char* argv[]){
|
|||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int run_file(char* filename){
|
||||
|
||||
FILE* file = fopen(filename, "r");
|
||||
if (file == NULL){
|
||||
printf("unable to open file '%s'\n", filename);
|
||||
|
|
@ -54,15 +49,17 @@ int run_file(char* filename){
|
|||
|
||||
fclose(file);
|
||||
|
||||
run(content);
|
||||
ScanResult scan_result = run(content);
|
||||
|
||||
// FREE UP
|
||||
free(content);
|
||||
|
||||
if (had_error){
|
||||
if (scan_result.had_error){
|
||||
return 65;
|
||||
}
|
||||
|
||||
tokenlist_print(&scan_result.token_list);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
@ -78,86 +75,12 @@ void run_prompt(void){
|
|||
}
|
||||
|
||||
int len =(int)strlen(line);
|
||||
run(substring(line, 1, len-1));
|
||||
had_error = false;
|
||||
ScanResult scan_result = run(substring(line, 1, len-1));
|
||||
|
||||
tokenlist_print(&scan_result.token_list);
|
||||
}
|
||||
}
|
||||
|
||||
void run(char* 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);
|
||||
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;
|
||||
ScanResult run(char* source){
|
||||
return scan_tokens(source);
|
||||
}
|
||||
|
|
|
|||
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