init
Author: Simon <sfja.skp@edu.mercantec.dk>
This commit is contained in:
commit
26a4153f01
9
.clang-format
Normal file
9
.clang-format
Normal file
@ -0,0 +1,9 @@
|
||||
BasedOnStyle: WebKit
|
||||
IndentWidth: 4
|
||||
ColumnLimit: 80
|
||||
IndentCaseLabels: true
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterFunction: true
|
||||
SplitEmptyFunction: false
|
||||
|
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
compile_flags.txt
|
||||
cli
|
||||
*.o
|
||||
|
25
Makefile
Normal file
25
Makefile
Normal file
@ -0,0 +1,25 @@
|
||||
|
||||
CFLAGS = -std=c17 -Wall -Wextra -Wpedantic -Wconversion
|
||||
LFLAGS = -lm
|
||||
|
||||
SRC = $(wildcard *.c)
|
||||
OBJ = $(patsubst %.c, %.o, $(SRC))
|
||||
|
||||
HEADERS = $(wildcard *.h)
|
||||
|
||||
TARGET = cli
|
||||
|
||||
all: compile_flags.txt$(TARGET)
|
||||
|
||||
$(TARGET): $(OBJ)
|
||||
gcc $^ -o $@ $(LFLAGS)
|
||||
|
||||
%.o: %.c $(HEADERS)
|
||||
gcc $< -c -o $@ $(CFLAGS)
|
||||
|
||||
clean:
|
||||
$(RM) *.o $(TARGET)
|
||||
|
||||
compile_flags.txt:
|
||||
echo -xc $(CPP_FLAGS) | sed 's/\s\+/\n/g' > compile_flags.txt
|
||||
|
140
main.c
Normal file
140
main.c
Normal file
@ -0,0 +1,140 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef enum {
|
||||
TokenTypeEof,
|
||||
TokenTypeNewline,
|
||||
TokenTypeSemicolon,
|
||||
TokenTypePlus,
|
||||
TokenTypeInt,
|
||||
TokenTypeId,
|
||||
} TokenType;
|
||||
|
||||
typedef struct {
|
||||
TokenType type;
|
||||
size_t index, length;
|
||||
int line, column;
|
||||
} Token;
|
||||
|
||||
typedef struct {
|
||||
size_t index;
|
||||
int line, column;
|
||||
} LexerPosition;
|
||||
|
||||
typedef struct {
|
||||
const char* text;
|
||||
size_t length;
|
||||
LexerPosition position;
|
||||
} Lexer;
|
||||
|
||||
void construct_lexer(Lexer* self, const char* text, size_t length)
|
||||
{
|
||||
*self = (Lexer) {
|
||||
.text = text,
|
||||
.length = length,
|
||||
.position = {
|
||||
.index = 0,
|
||||
.line = 1,
|
||||
.column = 1,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
bool is_whitespace_char(char c) { return c == ' ' || c == '\t'; }
|
||||
bool is_int_char(char c) { return c >= '0' && c <= '9'; }
|
||||
bool is_id_char(char c)
|
||||
{
|
||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'
|
||||
|| is_int_char(c);
|
||||
}
|
||||
|
||||
bool lexer_done(const Lexer* self)
|
||||
{
|
||||
return self->position.index >= self->length;
|
||||
}
|
||||
|
||||
void lexer_step(Lexer* self)
|
||||
{
|
||||
if (self->text[self->position.index] == '\n') {
|
||||
self->position.line += 1;
|
||||
self->position.column = 1;
|
||||
} else {
|
||||
self->position.column += 1;
|
||||
}
|
||||
self->position.index += 1;
|
||||
}
|
||||
|
||||
char lexer_current(const Lexer* self)
|
||||
{
|
||||
return self->text[self->position.index];
|
||||
}
|
||||
|
||||
LexerPosition lexer_position(const Lexer* self) { return self->position; }
|
||||
|
||||
Token lexer_token_from(const Lexer* self, TokenType type, LexerPosition start)
|
||||
{
|
||||
return (Token) {
|
||||
.type = type,
|
||||
.index = start.index,
|
||||
.length = self->position.index,
|
||||
.line = start.line,
|
||||
.column = start.column,
|
||||
};
|
||||
}
|
||||
|
||||
void lexer_skip_whitespace(Lexer* self)
|
||||
{
|
||||
lexer_step(self);
|
||||
while (!lexer_done(self) && is_whitespace_char(lexer_current(self)))
|
||||
lexer_step(self);
|
||||
}
|
||||
|
||||
Token lexer_make_int_token(Lexer* self)
|
||||
{
|
||||
LexerPosition start = self->position;
|
||||
lexer_step(self);
|
||||
while (!lexer_done(self) && is_int_char(lexer_current(self)))
|
||||
lexer_step(self);
|
||||
return lexer_token_from(self, TokenTypeInt, start);
|
||||
}
|
||||
|
||||
Token lexer_make_id_token(Lexer* self)
|
||||
{
|
||||
LexerPosition start = self->position;
|
||||
lexer_step(self);
|
||||
while (!lexer_done(self) && is_id_char(lexer_current(self)))
|
||||
lexer_step(self);
|
||||
return lexer_token_from(self, TokenTypeId, start);
|
||||
}
|
||||
|
||||
Token lexer_make_static_token(Lexer* self)
|
||||
{
|
||||
switch (lexer_current(self)) {
|
||||
case '\n':
|
||||
|
||||
default:
|
||||
printf("unrecognized char '%c'\n", lexer_current(self));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
Token lexer_make_token(Lexer* self)
|
||||
{
|
||||
if (lexer_done(self)) {
|
||||
return lexer_token_from(self, TokenTypeEof, lexer_position(self));
|
||||
} else if (is_whitespace_char(lexer_current(self))) {
|
||||
lexer_skip_whitespace(self);
|
||||
return lexer_make_token(self);
|
||||
} else if (is_int_char(lexer_current(self))) {
|
||||
return lexer_make_int_token(self);
|
||||
} else if (is_id_char(is_int_char(lexer_current(self)))) {
|
||||
return lexer_make_id_token(self);
|
||||
} else {
|
||||
return lexer_make_static_token(self);
|
||||
};
|
||||
}
|
||||
|
||||
Token lexer_next(Lexer* self) { return lexer_make_token(self); }
|
||||
|
||||
int main() { printf("hello world\n"); }
|
Loading…
Reference in New Issue
Block a user