lexer
This commit is contained in:
		
							parent
							
								
									2f1b2b50d5
								
							
						
					
					
						commit
						ae098219b3
					
				
							
								
								
									
										14
									
								
								.clang-format
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								.clang-format
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,14 @@
 | 
			
		||||
BasedOnStyle: WebKit
 | 
			
		||||
IndentWidth: 4
 | 
			
		||||
ColumnLimit: 80
 | 
			
		||||
IndentCaseLabels: true
 | 
			
		||||
BreakBeforeBraces: Custom
 | 
			
		||||
BraceWrapping:
 | 
			
		||||
    AfterFunction: true
 | 
			
		||||
    SplitEmptyFunction: false
 | 
			
		||||
AlignAfterOpenBracket: BlockIndent
 | 
			
		||||
AlignOperands: AlignAfterOperator
 | 
			
		||||
BreakBeforeBinaryOperators: true
 | 
			
		||||
BinPackArguments: false
 | 
			
		||||
BinPackParameters: false
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
			
		||||
matemateak
 | 
			
		||||
*.o
 | 
			
		||||
compile_flags.txt
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										23
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
			
		||||
 | 
			
		||||
CC = gcc
 | 
			
		||||
 | 
			
		||||
CFLAGS = -std=c17 -Wall -Wextra -Wpedantic -Wconversion
 | 
			
		||||
LFLAGS = -lm
 | 
			
		||||
 | 
			
		||||
C_FILES = $(shell find src/ -name *.c)
 | 
			
		||||
HEADER_FILES = $(shell find src/ -name *.h)
 | 
			
		||||
 | 
			
		||||
OBJECT_FILES = $(patsubst %.c, %.o, $(C_FILES))
 | 
			
		||||
 | 
			
		||||
matemateak: $(OBJECT_FILES)
 | 
			
		||||
	$(CC) -o $@ $(LFLAGS) $^
 | 
			
		||||
 | 
			
		||||
%.o: %.c $(HEADER_FILES)
 | 
			
		||||
	$(CC) -c -o $@ $(CFLAGS) $<
 | 
			
		||||
 | 
			
		||||
compile_flags.txt:
 | 
			
		||||
	echo -xc $(C_FLAGS) | sed 's/\s\+/\n/g' > compile_flags.txt
 | 
			
		||||
 | 
			
		||||
clean:
 | 
			
		||||
	$(RM) $(OBJECT_FILES) matemateak
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										123
									
								
								src/lexer.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								src/lexer.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,123 @@
 | 
			
		||||
#include "lexer.h"
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
bool lexer_done(const Lexer* lexer) { return lexer->index >= lexer->length; }
 | 
			
		||||
 | 
			
		||||
char lexer_current(const Lexer* lexer) { return lexer->text[lexer->index]; }
 | 
			
		||||
 | 
			
		||||
void lexer_step(Lexer* lexer)
 | 
			
		||||
{
 | 
			
		||||
    lexer->index += 1;
 | 
			
		||||
    if (!lexer_done(lexer)) {
 | 
			
		||||
        if (lexer_current(lexer) == '\n') {
 | 
			
		||||
            lexer->line += 1;
 | 
			
		||||
            lexer->col = 1;
 | 
			
		||||
        } else {
 | 
			
		||||
            lexer->col += 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Position lexer_pos(const Lexer* lexer)
 | 
			
		||||
{
 | 
			
		||||
    return (Position) {
 | 
			
		||||
        .index = lexer->index,
 | 
			
		||||
        .line = lexer->line,
 | 
			
		||||
        .col = lexer->col,
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Token lexer_token(const Lexer* lexer, TokenType type, Position start)
 | 
			
		||||
{
 | 
			
		||||
    return (Token) {
 | 
			
		||||
        .type = type,
 | 
			
		||||
        .index = start.index,
 | 
			
		||||
        .length = lexer->index - start.index,
 | 
			
		||||
        .line = start.line,
 | 
			
		||||
        .col = start.col,
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Token lexer_step_and_token(Lexer* lexer, TokenType type, Position start)
 | 
			
		||||
{
 | 
			
		||||
    lexer_step(lexer);
 | 
			
		||||
    return lexer_token(lexer, type, start);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool lexer_is_whitespace(char value)
 | 
			
		||||
{
 | 
			
		||||
    return value == ' ' || value == '\t' || value == '\r' || value == '\n';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Token lexer_skip_whitespace(Lexer* lexer)
 | 
			
		||||
{
 | 
			
		||||
    lexer_step(lexer);
 | 
			
		||||
    while (!lexer_done(lexer) && lexer_is_whitespace(lexer_current(lexer)))
 | 
			
		||||
        lexer_step(lexer);
 | 
			
		||||
    return lexer_next(lexer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool lexer_is_int(char value) { return value >= '0' && value <= '9'; }
 | 
			
		||||
 | 
			
		||||
bool lexer_is_int_start(char value) { return lexer_is_int(value); }
 | 
			
		||||
 | 
			
		||||
Token lexer_int_token(Lexer* lexer)
 | 
			
		||||
{
 | 
			
		||||
    Position start = lexer_pos(lexer);
 | 
			
		||||
    lexer_step(lexer);
 | 
			
		||||
    while (!lexer_done(lexer) && lexer_is_int(lexer_current(lexer)))
 | 
			
		||||
        lexer_step(lexer);
 | 
			
		||||
    return lexer_token(lexer, TokenTypeInt, start);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lexer(Lexer* lexer, const char* text, size_t length)
 | 
			
		||||
{
 | 
			
		||||
    *lexer = (Lexer) {
 | 
			
		||||
        .text = text,
 | 
			
		||||
        .length = length,
 | 
			
		||||
        .index = 0,
 | 
			
		||||
        .line = 1,
 | 
			
		||||
        .col = 1,
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Token lexer_level3(Lexer* lexer)
 | 
			
		||||
{
 | 
			
		||||
    if (lexer_is_int_start(lexer_current(lexer)))
 | 
			
		||||
        return lexer_int_token(lexer);
 | 
			
		||||
    else
 | 
			
		||||
        return lexer_step_and_token(
 | 
			
		||||
            lexer, TokenTypeInvalidChar, lexer_pos(lexer)
 | 
			
		||||
        );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Token lexer_level2(Lexer* lexer)
 | 
			
		||||
{
 | 
			
		||||
    Position start = lexer_pos(lexer);
 | 
			
		||||
    switch (lexer_current(lexer)) {
 | 
			
		||||
        case '+':
 | 
			
		||||
            return lexer_step_and_token(lexer, TokenTypePlus, start);
 | 
			
		||||
        case '-':
 | 
			
		||||
            return lexer_step_and_token(lexer, TokenTypeMinus, start);
 | 
			
		||||
        case '*':
 | 
			
		||||
            return lexer_step_and_token(lexer, TokenTypeAsterisk, start);
 | 
			
		||||
        case '/':
 | 
			
		||||
            return lexer_step_and_token(lexer, TokenTypeSlash, start);
 | 
			
		||||
        case '(':
 | 
			
		||||
            return lexer_step_and_token(lexer, TokenTypeLParen, start);
 | 
			
		||||
        case ')':
 | 
			
		||||
            return lexer_step_and_token(lexer, TokenTypeRParen, start);
 | 
			
		||||
        default:
 | 
			
		||||
            return lexer_level3(lexer);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Token lexer_next(Lexer* lexer)
 | 
			
		||||
{
 | 
			
		||||
    if (lexer_done(lexer))
 | 
			
		||||
        return lexer_token(lexer, TokenTypeEof, lexer_pos(lexer));
 | 
			
		||||
    else if (lexer_is_whitespace(lexer_current(lexer)))
 | 
			
		||||
        return lexer_skip_whitespace(lexer);
 | 
			
		||||
    else
 | 
			
		||||
        return lexer_level2(lexer);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										38
									
								
								src/lexer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/lexer.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,38 @@
 | 
			
		||||
#ifndef LEXER_H
 | 
			
		||||
#define LEXER_H
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    size_t index;
 | 
			
		||||
    int line, col;
 | 
			
		||||
} Position;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    TokenTypeEof,
 | 
			
		||||
    TokenTypeInvalidChar,
 | 
			
		||||
    TokenTypeInt,
 | 
			
		||||
    TokenTypePlus,
 | 
			
		||||
    TokenTypeMinus,
 | 
			
		||||
    TokenTypeAsterisk,
 | 
			
		||||
    TokenTypeSlash,
 | 
			
		||||
    TokenTypeLParen,
 | 
			
		||||
    TokenTypeRParen,
 | 
			
		||||
} TokenType;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    TokenType type;
 | 
			
		||||
    size_t index, length;
 | 
			
		||||
    int line, col;
 | 
			
		||||
} Token;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    const char* text;
 | 
			
		||||
    size_t index, length;
 | 
			
		||||
    int line, col;
 | 
			
		||||
} Lexer;
 | 
			
		||||
 | 
			
		||||
void lexer(Lexer* lexer, const char* text, size_t length);
 | 
			
		||||
Token lexer_next(Lexer* lexer);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										4
									
								
								src/main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/main.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
int main(void) { printf("hello world\n"); }
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user