add phase 1,2 and some of 3
This commit is contained in:
parent
cbc7fa34f3
commit
1f68be0479
6
examples/hello.c
Normal file
6
examples/hello.c
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
printf("hello\n");
|
||||||
|
}
|
||||||
184
parse.c
Normal file
184
parse.c
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
#include "parse.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// phases:
|
||||||
|
// https://en.cppreference.com/c/language/translation_phases
|
||||||
|
|
||||||
|
// phase 1 - source chars
|
||||||
|
|
||||||
|
void source_char_iter_init(SourceCharIter* r, const char* text)
|
||||||
|
{
|
||||||
|
*r = (SourceCharIter) {
|
||||||
|
.text = text,
|
||||||
|
.i = 0,
|
||||||
|
.line = 1,
|
||||||
|
.col = 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceChar source_iter_next(SourceCharIter* r)
|
||||||
|
{
|
||||||
|
char ch = r->text[r->i];
|
||||||
|
int line = r->line;
|
||||||
|
int col = r->col;
|
||||||
|
|
||||||
|
if (r->text[r->i] != '\0') {
|
||||||
|
if (ch == '\n') {
|
||||||
|
r->line += 1;
|
||||||
|
r->col = 1;
|
||||||
|
} else {
|
||||||
|
r->col += 1;
|
||||||
|
}
|
||||||
|
r->i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (SourceChar) { ch, line, col };
|
||||||
|
}
|
||||||
|
|
||||||
|
// phase 2 - logical source lines
|
||||||
|
|
||||||
|
void lsl_iter_init(LslCharIter* r, SourceCharIter* source_char_iter)
|
||||||
|
{
|
||||||
|
SourceChar curr = source_iter_next(source_char_iter);
|
||||||
|
|
||||||
|
*r = (LslCharIter) {
|
||||||
|
.source_char_iter = source_char_iter,
|
||||||
|
.curr = curr,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
LslChar lsl_iter_next(LslCharIter* r)
|
||||||
|
{
|
||||||
|
SourceChar next = source_iter_next(r->source_char_iter);
|
||||||
|
|
||||||
|
if (r->curr.ch == '\\' && next.ch == '\n') {
|
||||||
|
r->curr = source_iter_next(r->source_char_iter);
|
||||||
|
return lsl_iter_next(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
LslChar lsl_char = { r->curr.ch, r->curr.line, r->curr.col };
|
||||||
|
|
||||||
|
r->curr = next;
|
||||||
|
return lsl_char;
|
||||||
|
}
|
||||||
|
|
||||||
|
// phase 3 - preprocessor tokens
|
||||||
|
|
||||||
|
void lexer_init(Lexer* r, LslCharIter* lsl_char_iter)
|
||||||
|
{
|
||||||
|
LslChar curr = lsl_iter_next(lsl_char_iter);
|
||||||
|
|
||||||
|
*r = (Lexer) {
|
||||||
|
.lsl_char_iter = lsl_char_iter,
|
||||||
|
.curr = curr,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static Tok tok(TokTy ty, const char* text, int line, int col)
|
||||||
|
{
|
||||||
|
return (Tok) { ty, strdup(text), line, col };
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool l_done(Lexer* l)
|
||||||
|
{
|
||||||
|
return l->curr.ch == '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr size_t max_token_text_len = 64;
|
||||||
|
|
||||||
|
static void l_step(Lexer* l, char text[], size_t* text_len)
|
||||||
|
{
|
||||||
|
assert(*text_len < max_token_text_len);
|
||||||
|
text[*text_len] = l->curr.ch;
|
||||||
|
*text_len += 1;
|
||||||
|
|
||||||
|
l->curr = lsl_iter_next(l->lsl_char_iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
Tok lexer_next(Lexer* l)
|
||||||
|
{
|
||||||
|
int line = l->curr.line;
|
||||||
|
int col = l->curr.col;
|
||||||
|
|
||||||
|
char text[max_token_text_len] = "";
|
||||||
|
size_t text_len = 0;
|
||||||
|
|
||||||
|
if (l_done(l)) {
|
||||||
|
return tok(Tok_Eof, text, line, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool matched = false;
|
||||||
|
while (strchr(" \t\r", l->curr.ch)) {
|
||||||
|
matched = true;
|
||||||
|
l_step(l, text, &text_len);
|
||||||
|
}
|
||||||
|
if (matched) {
|
||||||
|
return lexer_next(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((l->curr.ch >= 'a' && l->curr.ch <= 'z')
|
||||||
|
|| (l->curr.ch >= 'A' && l->curr.ch <= 'Z')
|
||||||
|
|| (matched && l->curr.ch >= '0' && l->curr.ch <= '9')
|
||||||
|
|| strchr("_", l->curr.ch)) {
|
||||||
|
matched = true;
|
||||||
|
l_step(l, text, &text_len);
|
||||||
|
}
|
||||||
|
if (matched) {
|
||||||
|
return tok(Tok_Ident, text, line, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((l->curr.ch >= '1' && l->curr.ch <= '9')
|
||||||
|
|| (matched && l->curr.ch == '0')) {
|
||||||
|
matched = true;
|
||||||
|
l_step(l, text, &text_len);
|
||||||
|
}
|
||||||
|
if (matched) {
|
||||||
|
return tok(Tok_Int, text, line, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (l->curr.ch == '"') {
|
||||||
|
l_step(l, text, &text_len);
|
||||||
|
while (l->curr.ch != '"') {
|
||||||
|
if (l->curr.ch == '\\') {
|
||||||
|
l_step(l, text, &text_len);
|
||||||
|
if (l_done(l))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
l_step(l, text, &text_len);
|
||||||
|
}
|
||||||
|
if (l_done(l) || l->curr.ch != '"') {
|
||||||
|
fprintf(stderr, "error: malformed string literal\n");
|
||||||
|
return lexer_next(l);
|
||||||
|
}
|
||||||
|
l_step(l, text, &text_len);
|
||||||
|
return tok(Tok_Str, text, line, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (l->curr.ch == '\'') {
|
||||||
|
l_step(l, text, &text_len);
|
||||||
|
if (l->curr.ch == '\\') {
|
||||||
|
l_step(l, text, &text_len);
|
||||||
|
}
|
||||||
|
if (!l_done(l)) {
|
||||||
|
l_step(l, text, &text_len);
|
||||||
|
}
|
||||||
|
if (l_done(l) && l->curr.ch != '\'') {
|
||||||
|
fprintf(stderr, "error: malformed character literal\n");
|
||||||
|
return lexer_next(l);
|
||||||
|
}
|
||||||
|
l_step(l, text, &text_len);
|
||||||
|
return tok(Tok_Char, text, line, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strchr("\n;(){}", l->curr.ch)) {
|
||||||
|
TokTy ty = (TokTy)l->curr.ch;
|
||||||
|
l_step(l, text, &text_len);
|
||||||
|
return tok(ty, text, line, col);
|
||||||
|
}
|
||||||
|
fprintf(stderr, "error: illegal character '%c'\n", l->curr.ch);
|
||||||
|
l_step(l, text, &text_len);
|
||||||
|
return lexer_next(l);
|
||||||
|
}
|
||||||
67
parse.h
Normal file
67
parse.h
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#ifndef PARSE_H
|
||||||
|
#define PARSE_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char ch;
|
||||||
|
int line;
|
||||||
|
int col;
|
||||||
|
} SourceChar;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char* text;
|
||||||
|
size_t i;
|
||||||
|
int line;
|
||||||
|
int col;
|
||||||
|
} SourceCharIter;
|
||||||
|
|
||||||
|
void source_char_iter_init(SourceCharIter* r, const char* text);
|
||||||
|
SourceChar source_iter_next(SourceCharIter* r);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char ch;
|
||||||
|
int line;
|
||||||
|
int col;
|
||||||
|
} LslChar;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
SourceCharIter* source_char_iter;
|
||||||
|
SourceChar curr;
|
||||||
|
} LslCharIter;
|
||||||
|
|
||||||
|
void lsl_iter_init(LslCharIter* r, SourceCharIter* source_char_iter);
|
||||||
|
LslChar lsl_iter_next(LslCharIter* r);
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
Tok_Eof,
|
||||||
|
Tok_Eol,
|
||||||
|
Tok_Ident,
|
||||||
|
Tok_Int,
|
||||||
|
Tok_Str,
|
||||||
|
Tok_Char,
|
||||||
|
Tok_HeaderName,
|
||||||
|
Tok_Newline = '\n', // NOTE: has value 10
|
||||||
|
Tok_Semicolon = ';',
|
||||||
|
Tok_LParen = '(',
|
||||||
|
Tok_RParen = ')',
|
||||||
|
Tok_LBrace = '{',
|
||||||
|
Tok_RBrace = '}',
|
||||||
|
} TokTy;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
TokTy ty;
|
||||||
|
char* text;
|
||||||
|
int line;
|
||||||
|
int col;
|
||||||
|
} Tok;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
LslCharIter* lsl_char_iter;
|
||||||
|
LslChar curr;
|
||||||
|
} Lexer;
|
||||||
|
|
||||||
|
void lexer_init(Lexer* r, LslCharIter* lsl_char_iter);
|
||||||
|
Tok lexer_next(Lexer* l);
|
||||||
|
|
||||||
|
#endif
|
||||||
Loading…
x
Reference in New Issue
Block a user