strings and numbers
This commit is contained in:
parent
6e84fea3d1
commit
f76a252bd4
2 changed files with 243 additions and 79 deletions
|
|
@ -11,6 +11,11 @@ void error(char *message);
|
||||||
void report(char *where, char *message);
|
void report(char *where, char *message);
|
||||||
bool is_at_end(void);
|
bool is_at_end(void);
|
||||||
bool match(char expected);
|
bool match(char expected);
|
||||||
|
char peek(void);
|
||||||
|
char peek_next(void);
|
||||||
|
void string(void);
|
||||||
|
bool is_digit(char c);
|
||||||
|
void number(void);
|
||||||
|
|
||||||
bool had_error = false;
|
bool had_error = false;
|
||||||
int current_pos = -1;
|
int current_pos = -1;
|
||||||
|
|
@ -52,6 +57,16 @@ void add_token(enum TokenType type) {
|
||||||
tokenlist_add(&token_list, token);
|
tokenlist_add(&token_list, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void add_token_with_literal(enum TokenType type, char *literal) {
|
||||||
|
Token token;
|
||||||
|
token.type = type;
|
||||||
|
token.lexeme = substring(source, start, current_pos);
|
||||||
|
token.literal = literal;
|
||||||
|
token.line = current_line;
|
||||||
|
|
||||||
|
tokenlist_add(&token_list, token);
|
||||||
|
}
|
||||||
|
|
||||||
char advance(void) {
|
char advance(void) {
|
||||||
char c = source[current_pos++];
|
char c = source[current_pos++];
|
||||||
return c;
|
return c;
|
||||||
|
|
@ -97,12 +112,66 @@ void scan_token(void) {
|
||||||
case '<':
|
case '<':
|
||||||
add_token(match('=') ? LESS_EQUAL : LESS);
|
add_token(match('=') ? LESS_EQUAL : LESS);
|
||||||
break;
|
break;
|
||||||
|
case '/':
|
||||||
|
if (match('/')) {
|
||||||
|
while (peek() != '\n' && !is_at_end()) {
|
||||||
|
advance();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
add_token(SLASH);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ' ':
|
||||||
|
case '\t':
|
||||||
|
case '\r':
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
current_line += 1;
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
string();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
error("Unexpected character.");
|
if (is_digit(c)) {
|
||||||
|
number();
|
||||||
|
} else {
|
||||||
|
error("Unexpected character.");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void number(void) {
|
||||||
|
while (is_digit(peek()))
|
||||||
|
advance();
|
||||||
|
if (peek() == '.' && is_digit((peek_next())))
|
||||||
|
advance();
|
||||||
|
while (is_digit(peek()))
|
||||||
|
advance();
|
||||||
|
add_token_with_literal(NUMBER,
|
||||||
|
substring(source, start + 1, current_pos - start));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_digit(char c) { return c >= '0' && c <= '9'; }
|
||||||
|
|
||||||
|
void string(void) {
|
||||||
|
while (peek() != '"' && !is_at_end()) {
|
||||||
|
if (peek() == '\n')
|
||||||
|
current_line += 1;
|
||||||
|
advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_at_end()) {
|
||||||
|
error("Unterminated string.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
advance();
|
||||||
|
|
||||||
|
char *string = substring(source, start + 2, current_pos - start - 2);
|
||||||
|
add_token_with_literal(STRING, string);
|
||||||
|
}
|
||||||
|
|
||||||
bool match(char expected) {
|
bool match(char expected) {
|
||||||
if (is_at_end()) {
|
if (is_at_end()) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -114,6 +183,20 @@ bool match(char expected) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char peek_next(void) {
|
||||||
|
if (current_pos + 1 >= (int)strlen(source)) {
|
||||||
|
return '\0';
|
||||||
|
}
|
||||||
|
return source[current_pos + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
char peek(void) {
|
||||||
|
if (is_at_end()) {
|
||||||
|
return '\0';
|
||||||
|
}
|
||||||
|
return source[current_pos];
|
||||||
|
}
|
||||||
|
|
||||||
bool is_at_end(void) { return current_pos >= (int)strlen(source); }
|
bool is_at_end(void) { return current_pos >= (int)strlen(source); }
|
||||||
|
|
||||||
void error(char *message) { report("", message); }
|
void error(char *message) { report("", message); }
|
||||||
|
|
|
||||||
237
src/tokens.c
237
src/tokens.c
|
|
@ -1,83 +1,164 @@
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "tokens.h"
|
#include "tokens.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
char* token_name(Token* token){
|
char *token_name(Token *token) {
|
||||||
char* type;
|
char *type;
|
||||||
switch (token->type){
|
switch (token->type) {
|
||||||
case LEFT_PAREN: type = "LEFT_PAREN"; break;
|
case LEFT_PAREN:
|
||||||
case RIGHT_PAREN: type = "RIGHT_PAREN"; break;
|
type = "LEFT_PAREN";
|
||||||
case LEFT_BRACE: type = "LEFT_BRACE"; break;
|
break;
|
||||||
case RIGHT_BRACE: type = "RIGHT_BRACE"; break;
|
case RIGHT_PAREN:
|
||||||
case COMMA: type = "COMMA"; break;
|
type = "RIGHT_PAREN";
|
||||||
case DOT: type = "DOT"; break;
|
break;
|
||||||
case MINUS: type = "MINUS"; break;
|
case LEFT_BRACE:
|
||||||
case PLUS: type = "PLUS"; break;
|
type = "LEFT_BRACE";
|
||||||
case SEMICOLON: type = "SEMICOLON"; break;
|
break;
|
||||||
case SLASH: type = "SLASH"; break;
|
case RIGHT_BRACE:
|
||||||
case STAR: type = "STAR"; break;
|
type = "RIGHT_BRACE";
|
||||||
case BANG: type = "BANG"; break;
|
break;
|
||||||
case BANG_EQUAL: type = "BANG_EQUAL"; break;
|
case COMMA:
|
||||||
case EQUAL: type = "EQUAL"; break;
|
type = "COMMA";
|
||||||
case EQUAL_EQUAL: type = "EQUAL_EQUAL"; break;
|
break;
|
||||||
case GREATER: type = "GREATER"; break;
|
case DOT:
|
||||||
case GREATER_EQUAL: type = "GREATER_EQUAL"; break;
|
type = "DOT";
|
||||||
case LESS: type = "LESS"; break;
|
break;
|
||||||
case LESS_EQUAL: type = "LESS_EQUAL"; break;
|
case MINUS:
|
||||||
case IDENTIFIER: type = "IDENTIFIER"; break;
|
type = "MINUS";
|
||||||
case STRING: type = "STRING"; break;
|
break;
|
||||||
case NUMBER: type = "NUMBER"; break;
|
case PLUS:
|
||||||
case AND: type = "AND"; break;
|
type = "PLUS";
|
||||||
case CLASS: type = "CLASS"; break;
|
break;
|
||||||
case ELSE: type = "ELSE"; break;
|
case SEMICOLON:
|
||||||
case FALSE: type = "FALSE"; break;
|
type = "SEMICOLON";
|
||||||
case FUN: type = "FUN"; break;
|
break;
|
||||||
case FOR: type = "FOR"; break;
|
case SLASH:
|
||||||
case IF: type = "IF"; break;
|
type = "SLASH";
|
||||||
case NIL: type = "NIL"; break;
|
break;
|
||||||
case OR: type = "OR"; break;
|
case STAR:
|
||||||
case PRINT: type = "PRINT"; break;
|
type = "STAR";
|
||||||
case RETURN: type = "RETURN"; break;
|
break;
|
||||||
case SUPER: type = "SUPER"; break;
|
case BANG:
|
||||||
case THIS: type = "THIS"; break;
|
type = "BANG";
|
||||||
case TRUE: type = "TRUE"; break;
|
break;
|
||||||
case VAR: type = "VAR"; break;
|
case BANG_EQUAL:
|
||||||
case WHILE: type = "WHILE"; break;
|
type = "BANG_EQUAL";
|
||||||
case END_OF_FILE: type = "EOF"; break;
|
break;
|
||||||
|
case EQUAL:
|
||||||
|
type = "EQUAL";
|
||||||
|
break;
|
||||||
|
case EQUAL_EQUAL:
|
||||||
|
type = "EQUAL_EQUAL";
|
||||||
|
break;
|
||||||
|
case GREATER:
|
||||||
|
type = "GREATER";
|
||||||
|
break;
|
||||||
|
case GREATER_EQUAL:
|
||||||
|
type = "GREATER_EQUAL";
|
||||||
|
break;
|
||||||
|
case LESS:
|
||||||
|
type = "LESS";
|
||||||
|
break;
|
||||||
|
case LESS_EQUAL:
|
||||||
|
type = "LESS_EQUAL";
|
||||||
|
break;
|
||||||
|
case IDENTIFIER:
|
||||||
|
type = "IDENTIFIER";
|
||||||
|
break;
|
||||||
|
case STRING:
|
||||||
|
type = "STRING";
|
||||||
|
break;
|
||||||
|
case NUMBER:
|
||||||
|
type = "NUMBER";
|
||||||
|
break;
|
||||||
|
case AND:
|
||||||
|
type = "AND";
|
||||||
|
break;
|
||||||
|
case CLASS:
|
||||||
|
type = "CLASS";
|
||||||
|
break;
|
||||||
|
case ELSE:
|
||||||
|
type = "ELSE";
|
||||||
|
break;
|
||||||
|
case FALSE:
|
||||||
|
type = "FALSE";
|
||||||
|
break;
|
||||||
|
case FUN:
|
||||||
|
type = "FUN";
|
||||||
|
break;
|
||||||
|
case FOR:
|
||||||
|
type = "FOR";
|
||||||
|
break;
|
||||||
|
case IF:
|
||||||
|
type = "IF";
|
||||||
|
break;
|
||||||
|
case NIL:
|
||||||
|
type = "NIL";
|
||||||
|
break;
|
||||||
|
case OR:
|
||||||
|
type = "OR";
|
||||||
|
break;
|
||||||
|
case PRINT:
|
||||||
|
type = "PRINT";
|
||||||
|
break;
|
||||||
|
case RETURN:
|
||||||
|
type = "RETURN";
|
||||||
|
break;
|
||||||
|
case SUPER:
|
||||||
|
type = "SUPER";
|
||||||
|
break;
|
||||||
|
case THIS:
|
||||||
|
type = "THIS";
|
||||||
|
break;
|
||||||
|
case TRUE:
|
||||||
|
type = "TRUE";
|
||||||
|
break;
|
||||||
|
case VAR:
|
||||||
|
type = "VAR";
|
||||||
|
break;
|
||||||
|
case WHILE:
|
||||||
|
type = "WHILE";
|
||||||
|
break;
|
||||||
|
case END_OF_FILE:
|
||||||
|
type = "EOF";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tokenlist_init(TokenList *list) {
|
||||||
|
list->tokens = malloc(sizeof(Token) * 32);
|
||||||
|
list->size = 0;
|
||||||
|
list->capacity = 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tokenlist_add(TokenList *list, Token value) {
|
||||||
|
if (list->size >= list->capacity) {
|
||||||
|
list->capacity *= 2;
|
||||||
|
list->tokens = realloc(list->tokens, sizeof(Token) * list->capacity);
|
||||||
|
}
|
||||||
|
list->tokens[list->size] = value;
|
||||||
|
list->size += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Token *tokenlist_get(TokenList *list, int index) {
|
||||||
|
if (index >= list->size || index < 0) {
|
||||||
|
printf("Index %d out of bounds for list of size %d\n", index, list->size);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
return &list->tokens[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
void tokenlist_print(TokenList *tokenlist) {
|
||||||
|
for (int i = 0; i < tokenlist->size; i++) {
|
||||||
|
Token *token = tokenlist_get(tokenlist, i);
|
||||||
|
if (token->literal != NULL) {
|
||||||
|
printf("%s(%s), ", token_name(token), (char *)token->literal);
|
||||||
|
} else {
|
||||||
|
printf("%s, ", token_name(token));
|
||||||
}
|
}
|
||||||
return type;
|
}
|
||||||
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void tokenlist_init(TokenList* list){
|
void tokenlist_free(TokenList *list) { free(list->tokens); }
|
||||||
list->tokens = malloc(sizeof(Token) * 32);
|
|
||||||
list->size = 0;
|
|
||||||
list->capacity = 32;
|
|
||||||
}
|
|
||||||
|
|
||||||
void tokenlist_add(TokenList* list, Token value){
|
|
||||||
if (list->size >= list->capacity){
|
|
||||||
list->capacity *= 2;
|
|
||||||
list->tokens = realloc(list->tokens, sizeof(Token)* list->capacity);
|
|
||||||
}
|
|
||||||
list->tokens[list->size] = value;
|
|
||||||
list->size +=1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Token* tokenlist_get(TokenList* list, int index){
|
|
||||||
if (index >= list->size || index < 0){
|
|
||||||
printf("Index %d out of bounds for list of size %d\n", index, list->size);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
return &list->tokens[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
void tokenlist_print(TokenList* tokenlist){
|
|
||||||
for (int i=0; i< tokenlist->size; i++){
|
|
||||||
printf("%s, ", token_name(tokenlist_get(tokenlist, i)));
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void tokenlist_free(TokenList* list){
|
|
||||||
free(list->tokens);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue