Skip to content

Instantly share code, notes, and snippets.

@dbechrd
Last active May 30, 2020 20:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dbechrd/a177574f74ae579470e986fd63e09e04 to your computer and use it in GitHub Desktop.
Save dbechrd/a177574f74ae579470e986fd63e09e04 to your computer and use it in GitHub Desktop.
#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