Last active
May 30, 2020 20:33
-
-
Save dbechrd/a177574f74ae579470e986fd63e09e04 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include "../../dlb/dlb_vector.h" | |
// NOTE: Have to store as offset rather than pointer in case vector reallocs. Could use block allocator but wutevs man. | |
typedef struct String { | |
size_t offset; | |
size_t length; | |
} String; | |
typedef enum TokenType { | |
TOKEN_TYPE_INT, | |
TOKEN_TYPE_STRING, | |
TOKEN_TYPE_EOF | |
} TokenType; | |
typedef struct Token { | |
TokenType type; | |
union { | |
int as_int; | |
String as_string; | |
} data; | |
int line; | |
} Token; | |
static int is_digit(char c) | |
{ | |
return c >= '0' && c <= '9'; | |
} | |
static int is_lower(char c) | |
{ | |
return c >= 'a' && c <= 'z'; | |
} | |
// 1 <= T <= 20 (# of test cases) | |
// 1 <= N <= 1000 (length of strings) | |
// NOTE: The biggest number we need to parse is 1000, so we don't check for overflows | |
const char *parse_int(int *result, const char *input) | |
{ | |
if (!input) { | |
return 0; | |
} | |
const char *endptr = input; | |
int num = 0; | |
int i = 0; | |
while (is_digit(input[i])) { | |
num *= 10; | |
num += input[i] - '0'; | |
endptr++; | |
i++; | |
} | |
if (result) { | |
*result = num; | |
} | |
return endptr; | |
} | |
const char *parse_string(char **memory_arena, String *result, const char *input) | |
{ | |
if (!input) { | |
return 0; | |
} | |
const char *endptr = input; | |
size_t offset = dlb_vec_len(*memory_arena); | |
int i = 0; | |
while (is_lower(input[i])) { | |
dlb_vec_push(*memory_arena, input[i]); | |
endptr++; | |
i++; | |
} | |
dlb_vec_push(*memory_arena, 0); // nil-terminate strings | |
if (result) { | |
result->offset = offset; | |
result->length = dlb_vec_len(*memory_arena) - offset - 1; | |
} | |
return endptr; | |
} | |
void parse(char **memory_arena, Token **tokens, const char *input) | |
{ | |
int line = 1; | |
const char *cursor = input; | |
while (*cursor) { | |
if (is_digit(*cursor)) { | |
Token *token = dlb_vec_alloc(*tokens); | |
token->type = TOKEN_TYPE_INT; | |
cursor = parse_int(&token->data.as_int, cursor); | |
token->line = line; | |
} else if (is_lower(*cursor)) { | |
Token *token = dlb_vec_alloc(*tokens); | |
token->type = TOKEN_TYPE_STRING; | |
cursor = parse_string(memory_arena, &token->data.as_string, cursor); | |
token->line = line; | |
} else { | |
if (*cursor == '\n') { | |
line++; | |
} | |
cursor++; | |
} | |
} | |
Token *token = dlb_vec_alloc(*tokens); | |
token->type = TOKEN_TYPE_EOF; | |
token->line = line; | |
} | |
bool Consume(Token **result, Token **cursor, TokenType type) | |
{ | |
if ((*cursor)->type == type) { | |
*result = *cursor; | |
(*cursor)++; | |
return true; | |
} | |
return false; | |
} | |
bool ConsumeInt(int *result, Token **cursor) | |
{ | |
Token *token = 0; | |
if (Consume(&token, cursor, TOKEN_TYPE_INT)) { | |
if (result) { | |
*result = token->data.as_int; | |
} | |
return true; | |
} | |
return false; | |
} | |
bool ConsumeString(String *result, Token **cursor) | |
{ | |
Token *token = 0; | |
if (Consume(&token, cursor, TOKEN_TYPE_STRING)) { | |
if (result) { | |
result->offset = token->data.as_string.offset; | |
result->length = token->data.as_string.length; | |
} | |
return true; | |
} | |
return false; | |
} | |
typedef struct TestCase { | |
int n; // sanity check from input | |
String a; | |
String b; | |
} TestCase; | |
TestCase *test_cases; | |
int fatal(int code) | |
{ | |
#if _DEBUG | |
getchar(); | |
#endif | |
return code; | |
} | |
int success() | |
{ | |
#if _DEBUG | |
getchar(); | |
#endif | |
return 0; | |
} | |
int main(int argc, char *argv[]) | |
{ | |
// NOTE: Using dlb_vector as dynamic stack allocator for string storage | |
static char *string_arena; | |
// Vector of tokens | |
static Token *tokens; | |
const char *input = | |
"3\n" | |
"5\n" | |
"abcab\n" | |
"aabab\n" | |
"3\n" | |
"aaa\n" | |
"aab\n" | |
"2\n" | |
"de\n" | |
"cd"; | |
parse(&string_arena, &tokens, input); | |
dlb_vec_each(Token *, token, tokens) { | |
switch (token->type) { | |
case TOKEN_TYPE_INT: | |
printf("INT %d\n", token->data.as_int); | |
break; | |
case TOKEN_TYPE_STRING: | |
printf("STRING %.*s\n", token->data.as_string.length, string_arena + token->data.as_string.offset); | |
break; | |
} | |
} | |
printf("\n"); | |
Token *cursor = tokens; | |
int test_case_count = 0; | |
if (!ConsumeInt(&test_case_count, &cursor)) { | |
printf("[Line %d] error: expected test case count\n", cursor->line); | |
return fatal(-1); | |
} else if (test_case_count < 1 || test_case_count > 20) { | |
printf("[Line %d] error: expected test case count to be in range 1-20\n", cursor->line); | |
return fatal(-1); | |
} | |
dlb_vec_reserve(test_cases, (size_t)test_case_count); | |
while (cursor->type != TOKEN_TYPE_EOF) { | |
TestCase *test_case = dlb_vec_alloc(test_cases); | |
if (!ConsumeInt(&test_case->n, &cursor)) { | |
printf("[Line %d] error: expected string length (`N`)\n", cursor->line); | |
return fatal(-1); | |
} else if (test_case->n < 1 || test_case->n > 1000) { | |
printf("[Line %d] error: expected string length to be in range 1-1000\n", cursor->line); | |
return fatal(-1); | |
} | |
if (!ConsumeString(&test_case->a, &cursor)) { | |
printf("[Line %d] error: expected string (the `A` string of the test case)\n", cursor->line); | |
return fatal(-1); | |
} else if (test_case->a.length != test_case->n) { | |
printf("[Line %d] error: expected string length of `A` string to match `N` (%d != %d)\n", cursor->line, | |
test_case->a.length, test_case->n); | |
return fatal(-1); | |
} | |
if (!ConsumeString(&test_case->b, &cursor)) { | |
printf("[Line %d] error: expected string (the `B` string of the test case)\n", cursor->line); | |
return fatal(-1); | |
} else if (test_case->b.length != test_case->n) { | |
printf("[Line %d] error: expected string length of `B` string to match `N` (%d != %d)\n", cursor->line, | |
test_case->b.length, test_case->n); | |
return fatal(-1); | |
} | |
} | |
dlb_vec_each(TestCase *, test_case, test_cases) { | |
printf("Test Case:\n"); | |
printf(" N: %d\n", test_case->n); | |
printf(" A: %s (%d, %d)\n", string_arena + test_case->a.offset, test_case->a.offset, test_case->a.length); | |
printf(" B: %s (%d, %d)\n", string_arena + test_case->b.offset, test_case->b.offset, test_case->b.length); | |
// TODO: Solve the actual problem :D | |
} | |
return success(); | |
} | |
#define DLB_VECTOR_IMPLEMENTATION | |
#include "../../dlb/dlb_vector.h" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment