Implemented conversion from parse tree to SQL structure.
Added debug printing for SQL statements.
This commit is contained in:
154
src/SQL.c
154
src/SQL.c
@@ -3,10 +3,13 @@
|
||||
//
|
||||
|
||||
#include <malloc.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "SQL.h"
|
||||
|
||||
Value *new_value() {
|
||||
Value *value = malloc(sizeof(Value));
|
||||
value->type = VALUE_NONE;
|
||||
value->number = 0;
|
||||
value->string = NULL;
|
||||
return value;
|
||||
@@ -177,7 +180,7 @@ SelectStmt *new_select_stmt() {
|
||||
|
||||
void free_select_stmt(SelectStmt *stmt) {
|
||||
if (stmt->where != NULL) {
|
||||
free_assignment_list(stmt->where);
|
||||
free_comparison_group(stmt->where);
|
||||
}
|
||||
if (stmt->tableName != NULL) {
|
||||
free(stmt->tableName);
|
||||
@@ -218,7 +221,7 @@ void free_update_stmt(UpdateStmt *stmt) {
|
||||
free(stmt->tableName);
|
||||
}
|
||||
if (stmt->where != NULL) {
|
||||
free_assignment_list(stmt->where);
|
||||
free_comparison_group(stmt->where);
|
||||
}
|
||||
if (stmt->values != NULL) {
|
||||
free_assignment_list(stmt->values);
|
||||
@@ -237,7 +240,7 @@ void free_delete_stmt(DeleteStmt *stmt) {
|
||||
free(stmt->tableName);
|
||||
}
|
||||
if (stmt->where != NULL) {
|
||||
free_assignment_list(stmt->where);
|
||||
free_comparison_group(stmt->where);
|
||||
}
|
||||
free(stmt);
|
||||
}
|
||||
@@ -272,10 +275,10 @@ void free_drop_stmt(DropStmt *stmt) {
|
||||
free(stmt);
|
||||
}
|
||||
|
||||
Statement *new_statement() {
|
||||
Statement *new_statement(StatementType type, void *statement) {
|
||||
Statement *stmt = malloc(sizeof(Statement));
|
||||
stmt->type = STMT_NONE;
|
||||
stmt->stmt = NULL;
|
||||
stmt->type = type;
|
||||
stmt->stmt = statement;
|
||||
return stmt;
|
||||
}
|
||||
|
||||
@@ -330,4 +333,143 @@ void append_statement_list(StatementList *list, Statement *statement) {
|
||||
list->length++;
|
||||
list->statements = realloc(list->statements, sizeof(Statement *) * list->length);
|
||||
list->statements[list->length - 1] = statement;
|
||||
}
|
||||
|
||||
void print_statement_list(StatementList *list) {
|
||||
|
||||
for (size_t i = 0; i < list->length; i++) {
|
||||
Statement *stmt = list->statements[i];
|
||||
switch (stmt->type) {
|
||||
case STMT_SELECT: {
|
||||
SelectStmt *select = stmt->stmt;
|
||||
printf("SELECT ");
|
||||
print_field_list(select->fields);
|
||||
printf(" FROM %s", select->tableName);
|
||||
if (select->where->length > 0) {
|
||||
printf(" WHERE ");
|
||||
print_comparison_group(select->where);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case STMT_INSERT: {
|
||||
InsertStmt *insert = stmt->stmt;
|
||||
printf("INSERT INTO %s SET ", insert->tableName);
|
||||
print_assignment_list(insert->values);
|
||||
}
|
||||
break;
|
||||
case STMT_UPDATE: {
|
||||
UpdateStmt *update = stmt->stmt;
|
||||
printf("UPDATE %s SET ", update->tableName);
|
||||
print_assignment_list(update->values);
|
||||
if (update->where->length > 0) {
|
||||
printf(" WHERE ");
|
||||
print_comparison_group(update->where);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case STMT_DELETE: {
|
||||
DeleteStmt *delete = stmt->stmt;
|
||||
printf("DELETE FROM %s", delete->tableName);
|
||||
if (delete->where->length > 0) {
|
||||
printf(" ");
|
||||
print_comparison_group(delete->where);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case STMT_CREATE: {
|
||||
CreateStmt *create = stmt->stmt;
|
||||
printf("CREATE TABLE %s (", create->tableName);
|
||||
print_column_spec_list(create->columns);
|
||||
printf(")");
|
||||
}
|
||||
break;
|
||||
case STMT_DROP: {
|
||||
DropStmt *drop = stmt->stmt;
|
||||
printf("DELETE TABLE %s", drop->tableName);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
printf(";\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void print_field_list(FieldList *list) {
|
||||
for (size_t i = 0; i < list->length; i++) {
|
||||
printf("%s%s", list->fields[i], i + 1 < list->length ? ", " : "");
|
||||
}
|
||||
}
|
||||
|
||||
void print_assignment_list(AssignmentList *list) {
|
||||
for (size_t i = 0; i < list->length; i++) {
|
||||
Assignment *assignment = list->assignments[i];
|
||||
printf("%s=", assignment->identifier);
|
||||
print_value(assignment->value);
|
||||
if (i + 1 < list->length) {
|
||||
printf(", ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print_comparison_group(ComparisonGroup *group) {
|
||||
for (size_t i = 0; i < group->length; i++) {
|
||||
Comparison *comparison = group->comparisons[i];
|
||||
printf("%s=", comparison->identifier);
|
||||
print_value(comparison->value);
|
||||
if (i + 1 < group->length) {
|
||||
printf(" AND ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print_column_spec_list(ColumnSpecList *list) {
|
||||
for (size_t i = 0; i < list->length; i++) {
|
||||
ColumnSpec *spec = list->columns[i];
|
||||
if (spec->type == COLTYPE_STRING) {
|
||||
printf("%s STRING(%d)", spec->identifier, spec->size);
|
||||
} else if (spec->type == COLTYPE_INT) {
|
||||
printf("%s INTEGER", spec->identifier);
|
||||
}
|
||||
if (spec->option == COLOPT_INDEX) {
|
||||
printf(" INDEX");
|
||||
}
|
||||
if (i + 1 < list->length) {
|
||||
printf(", ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print_value(Value *value) {
|
||||
if (value->type == VALUE_STRING) {
|
||||
printf("'");
|
||||
size_t len = strlen(value->string);
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
char next = value->string[i];
|
||||
switch (next) {
|
||||
case '\'':
|
||||
printf("\\'");
|
||||
break;
|
||||
case '\n':
|
||||
printf("\\n");
|
||||
break;
|
||||
case '\r':
|
||||
printf("\\r");
|
||||
break;
|
||||
case '\t':
|
||||
printf("\\t");
|
||||
break;
|
||||
case '\\':
|
||||
printf("\\\\");
|
||||
break;
|
||||
default:
|
||||
printf("%c", next);
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("'");
|
||||
} else if (value->type == VALUE_NUMBER) {
|
||||
printf("%lld", value->number);
|
||||
}
|
||||
}
|
||||
41
src/SQL.h
41
src/SQL.h
@@ -8,11 +8,19 @@
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
union Value_t {
|
||||
char *string;
|
||||
uint64_t number;
|
||||
enum ValueType_t {
|
||||
VALUE_NONE,
|
||||
VALUE_STRING,
|
||||
VALUE_NUMBER
|
||||
};
|
||||
typedef union Value_t Value;
|
||||
typedef enum ValueType_t ValueType;
|
||||
|
||||
struct Value_t {
|
||||
ValueType type;
|
||||
char *string;
|
||||
int64_t number;
|
||||
};
|
||||
typedef struct Value_t Value;
|
||||
|
||||
Value *new_value();
|
||||
|
||||
@@ -33,6 +41,7 @@ struct Comparison_t {
|
||||
typedef struct Comparison_t Comparison;
|
||||
|
||||
Comparison *new_comparison();
|
||||
|
||||
void free_comparison(Comparison *comparison);
|
||||
|
||||
struct ComparisonGroup_t {
|
||||
@@ -42,7 +51,9 @@ struct ComparisonGroup_t {
|
||||
typedef struct ComparisonGroup_t ComparisonGroup;
|
||||
|
||||
ComparisonGroup *new_comparision_group();
|
||||
void free_comparison_group(ComparisonGroup* group);
|
||||
|
||||
void free_comparison_group(ComparisonGroup *group);
|
||||
|
||||
void append_comparison_group(ComparisonGroup *group, Comparison *comparison);
|
||||
|
||||
struct Assignment_t {
|
||||
@@ -119,7 +130,7 @@ void append_column_spec_list(ColumnSpecList *list, ColumnSpec *spec);
|
||||
struct SelectStmt_t {
|
||||
FieldList *fields;
|
||||
char *tableName;
|
||||
AssignmentList *where;
|
||||
ComparisonGroup *where;
|
||||
};
|
||||
typedef struct SelectStmt_t SelectStmt;
|
||||
|
||||
@@ -140,7 +151,7 @@ void free_insert_stmt(InsertStmt *stmt);
|
||||
struct UpdateStmt_t {
|
||||
char *tableName;
|
||||
AssignmentList *values;
|
||||
AssignmentList *where;
|
||||
ComparisonGroup *where;
|
||||
};
|
||||
typedef struct UpdateStmt_t UpdateStmt;
|
||||
|
||||
@@ -150,7 +161,7 @@ void free_update_stmt(UpdateStmt *stmt);
|
||||
|
||||
struct DeleteStmt_t {
|
||||
char *tableName;
|
||||
AssignmentList *where;
|
||||
ComparisonGroup *where;
|
||||
};
|
||||
typedef struct DeleteStmt_t DeleteStmt;
|
||||
|
||||
@@ -194,7 +205,7 @@ struct Statement_t {
|
||||
};
|
||||
typedef struct Statement_t Statement;
|
||||
|
||||
Statement *new_statement();
|
||||
Statement *new_statement(StatementType type, void *statement);
|
||||
|
||||
void free_statement(Statement *stmt);
|
||||
|
||||
@@ -210,4 +221,16 @@ void free_statement_list(StatementList *list);
|
||||
|
||||
void append_statement_list(StatementList *list, Statement *statement);
|
||||
|
||||
void print_statement_list(StatementList *list);
|
||||
|
||||
void print_field_list(FieldList *list);
|
||||
|
||||
void print_assignment_list(AssignmentList *list);
|
||||
|
||||
void print_comparison_group(ComparisonGroup *group);
|
||||
|
||||
void print_column_spec_list(ColumnSpecList *list);
|
||||
|
||||
void print_value(Value *value);
|
||||
|
||||
#endif //SDB_SQL_H
|
||||
|
||||
@@ -36,6 +36,11 @@ void parse_input(char *input) {
|
||||
if (node != NULL) {
|
||||
printf("%s\n", input);
|
||||
parser_print_node_tree(node, 0);
|
||||
|
||||
StatementList* list = parser_node_convert(node);
|
||||
print_statement_list(list);
|
||||
free_statement_list(list);
|
||||
|
||||
free_parser_node(node);
|
||||
}
|
||||
|
||||
|
||||
153
src/parser.c
153
src/parser.c
@@ -76,6 +76,149 @@ void free_parser(Parser *parser) {
|
||||
free(parser);
|
||||
}
|
||||
|
||||
StatementList *parser_node_convert(ParserNode *node) {
|
||||
if (node->type != NODE_STATEMENT_LIST) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
StatementList *list = new_statement_list();
|
||||
|
||||
size_t i, k;
|
||||
|
||||
for (i = 0; i < node->childrenLength; i++) {
|
||||
ParserNode *child = node->children[i];
|
||||
switch (child->type) {
|
||||
case NODE_SELECT_STMT: {
|
||||
SelectStmt *select = new_select_stmt();
|
||||
append_statement_list(list, new_statement(STMT_SELECT, select));
|
||||
select->fields = new_field_list();
|
||||
select->tableName = strdup(child->children[1]->token->valueStr);
|
||||
for (k = 0; k < child->children[0]->childrenLength; k++) {
|
||||
ParserNode *fieldNode = child->children[0]->children[k];
|
||||
append_field_list(select->fields, strdup(fieldNode->token->valueStr));
|
||||
}
|
||||
if (child->childrenLength == 3) {
|
||||
select->where = parser_node_convert_comparison_group(child->children[2]);
|
||||
} else {
|
||||
select->where = new_comparision_group();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NODE_INSERT_STMT: {
|
||||
InsertStmt *insert = new_insert_stmt();
|
||||
append_statement_list(list, new_statement(STMT_INSERT, insert));
|
||||
insert->tableName = strdup(child->children[0]->token->valueStr);
|
||||
insert->values = parser_node_convert_assignment_list(child->children[1]);
|
||||
}
|
||||
break;
|
||||
case NODE_UPDATE_STMT: {
|
||||
UpdateStmt *update = new_update_stmt();
|
||||
append_statement_list(list, new_statement(STMT_UPDATE, update));
|
||||
update->tableName = strdup(child->children[0]->token->valueStr);
|
||||
update->values = parser_node_convert_assignment_list(child->children[1]);
|
||||
if (child->childrenLength == 3) {
|
||||
update->where = parser_node_convert_comparison_group(child->children[2]);
|
||||
} else {
|
||||
update->where = new_comparision_group();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NODE_DELETE_STMT: {
|
||||
DeleteStmt *delete = new_delete_stmt();
|
||||
append_statement_list(list, new_statement(STMT_DELETE, delete));
|
||||
delete->tableName = strdup(child->children[0]->token->valueStr);
|
||||
if (child->childrenLength == 2) {
|
||||
delete->where = parser_node_convert_comparison_group(child->children[1]);
|
||||
} else {
|
||||
delete->where = new_comparision_group();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NODE_CREATE_STMT: {
|
||||
CreateStmt *create = new_create_stmt();
|
||||
append_statement_list(list, new_statement(STMT_CREATE, create));
|
||||
create->tableName = strdup(child->children[0]->token->valueStr);
|
||||
create->columns = parser_node_convert_column_spec_list(child->children[1]);
|
||||
}
|
||||
break;
|
||||
case NODE_DROP_STMT: {
|
||||
DropStmt *drop= new_drop_stmt();
|
||||
append_statement_list(list, new_statement(STMT_DROP, drop));
|
||||
drop->tableName = (child->children[0]->token->valueStr);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
ColumnSpecList *parser_node_convert_column_spec_list(ParserNode *node) {
|
||||
ColumnSpecList *list = new_column_spec_list();
|
||||
for (size_t i = 0; i < node->childrenLength; i++) {
|
||||
ParserNode* specNode = node->children[i];
|
||||
ColumnSpec *spec = new_column_spec();
|
||||
append_column_spec_list(list, spec);
|
||||
spec->identifier = strdup(specNode->token->valueStr);
|
||||
ParserNode *colTypeNode = specNode->children[0];
|
||||
if (colTypeNode->token->type == T_KW_STRING) {
|
||||
spec->type = COLTYPE_STRING;
|
||||
spec->size = (size_t)colTypeNode->children[0]->token->valueInt;
|
||||
} else if (colTypeNode->token->type == T_KW_INT) {
|
||||
spec->type = COLTYPE_INT;
|
||||
}
|
||||
if (specNode->childrenLength == 2) {
|
||||
if (specNode->children[1]->token->type == T_KW_INDEX) {
|
||||
spec->option = COLOPT_INDEX;
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
ComparisonGroup *parser_node_convert_comparison_group(ParserNode *node) {
|
||||
ComparisonGroup *group = new_comparision_group();
|
||||
for (size_t i = 0; i < node->childrenLength; i++) {
|
||||
ParserNode *compNode = node->children[i];
|
||||
Comparison *comp = new_comparison();
|
||||
append_comparison_group(group, comp);
|
||||
comp->identifier = strdup(compNode->children[0]->token->valueStr);
|
||||
if (compNode->children[1]->token->type == T_COMP_EQ) {
|
||||
comp->comp = COMP_EQ;
|
||||
} else if (compNode->children[1]->token->type == T_COMP_NEQ) {
|
||||
comp->comp = COMP_NEQ;
|
||||
}
|
||||
comp->value = parser_node_convert_value(compNode->children[2]);
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
AssignmentList *parser_node_convert_assignment_list(ParserNode *node) {
|
||||
AssignmentList *list = new_assignment_list();
|
||||
for (size_t i = 0; i < node->childrenLength; i++) {
|
||||
ParserNode *assignmentNode = node->children[i];
|
||||
Assignment *assignment = new_assignment();
|
||||
append_assignment_list(list, assignment);
|
||||
assignment->identifier = strdup(assignmentNode->token->valueStr);
|
||||
assignment->value = parser_node_convert_value(assignmentNode->children[0]);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
Value *parser_node_convert_value(ParserNode *node) {
|
||||
Value *value = new_value();
|
||||
if (node->token->type == T_STRING) {
|
||||
value->type = VALUE_STRING;
|
||||
value->string = strdup(node->token->valueStr);
|
||||
} else if (node->token->type == T_NUMBER) {
|
||||
value->type = VALUE_NUMBER;
|
||||
value->number = node->token->valueInt;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
#define NEXT_TOKEN() {\
|
||||
token = scanner_next_token(scanner, token);\
|
||||
}
|
||||
@@ -286,9 +429,9 @@ ParserNode *parser_parse(Parser *parser, Scanner *scanner) {
|
||||
ASCEND_NODE();
|
||||
} else if (token->type == T_KW_WHERE) {
|
||||
node->phase++;
|
||||
ParserNode *assignments = new_parser_node(NODE_ASSIGNMENT_LIST, NULL);
|
||||
append_parser_node(node, assignments);
|
||||
node = assignments;
|
||||
ParserNode *comparisons = new_parser_node(NODE_COMPARISON_GROUP, NULL);
|
||||
append_parser_node(node, comparisons);
|
||||
node = comparisons;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -407,6 +550,10 @@ ParserNode *parser_parse(Parser *parser, Scanner *scanner) {
|
||||
parser_set_error(parser, "Expected number", token);
|
||||
break;
|
||||
}
|
||||
if (token->valueInt < 1) {
|
||||
parser_set_error(parser, "Expected positive number", token);
|
||||
break;
|
||||
}
|
||||
append_parser_node(columnType, new_parser_node(NODE_COLUMN_TYPE_SPECIFIER, token));
|
||||
token = NULL;
|
||||
EXPECT(T_PAREN_CLOSE);
|
||||
|
||||
12
src/parser.h
12
src/parser.h
@@ -55,7 +55,7 @@ enum ParserNodeType_t {
|
||||
typedef enum ParserNodeType_t ParserNodeType;
|
||||
#undef X
|
||||
|
||||
char* parser_node_type_to_str(ParserNodeType nodeType);
|
||||
char *parser_node_type_to_str(ParserNodeType nodeType);
|
||||
|
||||
struct ParserNode_t {
|
||||
struct ParserNode_t *parent;
|
||||
@@ -73,6 +73,16 @@ void free_parser_node(ParserNode *node);
|
||||
|
||||
void append_parser_node(ParserNode *node, ParserNode *child);
|
||||
|
||||
StatementList *parser_node_convert(ParserNode *node);
|
||||
|
||||
ColumnSpecList *parser_node_convert_column_spec_list(ParserNode *node);
|
||||
|
||||
ComparisonGroup *parser_node_convert_comparison_group(ParserNode *node);
|
||||
|
||||
AssignmentList *parser_node_convert_assignment_list(ParserNode *node);
|
||||
|
||||
Value *parser_node_convert_value(ParserNode *node);
|
||||
|
||||
struct Parser_t {
|
||||
ParseStatus status;
|
||||
char *errMsg;
|
||||
|
||||
@@ -203,11 +203,11 @@ ScannerToken *scanner_next_token(Scanner *scanner, ScannerToken *token) {
|
||||
}
|
||||
|
||||
//Numbers
|
||||
if (isdigit(scanner_peek_char(scanner))) {
|
||||
if (isdigit(scanner_peek_char(scanner)) || scanner_peek_char(scanner) == '-') {
|
||||
char intInput[32] = {0};
|
||||
size_t intIndex = 0;
|
||||
while (scanner_peek_char(scanner) != 0
|
||||
&& isdigit(scanner_peek_char(scanner))
|
||||
&& (isdigit(scanner_peek_char(scanner)) || scanner_peek_char(scanner) == '-')
|
||||
&& intIndex + 1 < 32) {
|
||||
intInput[intIndex++] = scanner_next_char(scanner);
|
||||
}
|
||||
@@ -219,7 +219,7 @@ ScannerToken *scanner_next_token(Scanner *scanner, ScannerToken *token) {
|
||||
}
|
||||
token->type = T_NUMBER;
|
||||
//convert number
|
||||
token->valueInt = (uint64_t) strtol(intInput, NULL, 10);
|
||||
token->valueInt = (int64_t) strtol(intInput, NULL, 10);
|
||||
return token;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ char* scanner_token_type_to_str(ScannerTokenType tokenType);
|
||||
struct ScannerToken_t {
|
||||
ScannerTokenType type;
|
||||
char *valueStr;
|
||||
uint64_t valueInt;
|
||||
int64_t valueInt;
|
||||
size_t lineNo;
|
||||
size_t linePos;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user