From: Michael D. Lowis Date: Fri, 26 Sep 2014 17:52:47 +0000 (-0400) Subject: Refactor code structure to have separate parser and grammar modules X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=bc0b0b8ca2c9aa7d4ab1a980acc8688b26f54b0c;p=proto%2Fsclpl.git Refactor code structure to have separate parser and grammar modules --- diff --git a/modules/libcds b/modules/libcds index 5550feb..a70643a 160000 --- a/modules/libcds +++ b/modules/libcds @@ -1 +1 @@ -Subproject commit 5550feb668fd728863039e50bd660e79236df5d0 +Subproject commit a70643a30382932f3eda4d2a5159e81664731bea diff --git a/modules/libopts b/modules/libopts index 11db084..9266387 160000 --- a/modules/libopts +++ b/modules/libopts @@ -1 +1 @@ -Subproject commit 11db084f5d5c49caa482341f5a83ba37918c9c8c +Subproject commit 9266387d534a8ca397824e07e62e390ca1dbb236 diff --git a/source/sclpl/grammar.c b/source/sclpl/grammar.c new file mode 100644 index 0000000..2de905b --- /dev/null +++ b/source/sclpl/grammar.c @@ -0,0 +1,108 @@ +/** + @file grammar.c + @brief See header for details + $Revision$ + $HeadURL$ + */ +#include "grammar.h" + +void grammar_toplevel(parser_t* p_parser) +{ + if (parser_accept_str(p_parser, T_VAR, "import")) + grammar_import(p_parser); + else if (parser_accept_str(p_parser, T_VAR, "def")) + grammar_definition(p_parser); + else if (p_parser->p_lexer->scanner->p_input == stdin) + grammar_expression(p_parser); + else + parser_error(p_parser, "Unrecognized top-level form"); +} + +void grammar_import(parser_t* p_parser) +{ + parser_expect(p_parser, T_VAR); + parser_expect(p_parser, T_END); +} + +void grammar_definition(parser_t* p_parser) +{ + parser_expect(p_parser,T_VAR); + if (parser_peek(p_parser)->type == T_LPAR) { + grammar_fn_stmnt(p_parser); + } else { + grammar_expression(p_parser); + parser_expect(p_parser,T_END); + } +} + +void grammar_expression(parser_t* p_parser) +{ + if (parser_accept(p_parser, T_LPAR)) { + grammar_expression(p_parser); + parser_accept(p_parser, T_RPAR); + } else if (parser_accept_str(p_parser, T_VAR, "if")) { + grammar_if_stmnt(p_parser); + } else if (parser_accept_str(p_parser, T_VAR, "fn")) { + grammar_fn_stmnt(p_parser); + } else if (parser_peek(p_parser)->type == T_VAR) { + parser_expect(p_parser, T_VAR); + if (parser_peek(p_parser)->type == T_LPAR) { + grammar_arglist(p_parser); + } + } else { + grammar_literal(p_parser); + } +} + +void grammar_literal(parser_t* p_parser) +{ + switch (parser_peek(p_parser)->type) + { + case T_BOOL: + case T_CHAR: + case T_STRING: + case T_INT: + case T_FLOAT: + parser_accept(p_parser, parser_peek(p_parser)->type); + break; + + default: + parser_error(p_parser, "Not a valid expression"); + break; + } +} + +void grammar_arglist(parser_t* p_parser) +{ + parser_expect(p_parser, T_LPAR); + while(parser_peek(p_parser)->type != T_RPAR) { + grammar_expression(p_parser); + if(parser_peek(p_parser)->type != T_RPAR) + parser_expect(p_parser, T_COMMA); + } + parser_expect(p_parser, T_RPAR); +} + +void grammar_if_stmnt(parser_t* p_parser) +{ + grammar_expression(p_parser); + grammar_expression(p_parser); + parser_expect_str(p_parser,T_VAR,"else"); + grammar_expression(p_parser); + parser_expect(p_parser,T_END); +} + +void grammar_fn_stmnt(parser_t* p_parser) +{ + parser_expect(p_parser, T_LPAR); + while(parser_peek(p_parser)->type != T_RPAR) { + parser_expect(p_parser, T_VAR); + if(parser_peek(p_parser)->type != T_RPAR) + parser_expect(p_parser, T_COMMA); + } + parser_expect(p_parser, T_RPAR); + while(parser_peek(p_parser)->type != T_END) { + grammar_expression(p_parser); + } + parser_expect(p_parser, T_END); +} diff --git a/source/sclpl/grammar.h b/source/sclpl/grammar.h new file mode 100644 index 0000000..3ac5088 --- /dev/null +++ b/source/sclpl/grammar.h @@ -0,0 +1,26 @@ +/** + @file grammar.h + @brief Describes the grammar and parsing rules that form the SCLPL language. +*/ +#ifndef GRAMMAR_H +#define GRAMMAR_H + +#include "parser.h" + +void grammar_toplevel(parser_t* p_parser); + +void grammar_import(parser_t* p_parser); + +void grammar_definition(parser_t* p_parser); + +void grammar_expression(parser_t* p_parser); + +void grammar_literal(parser_t* p_parser); + +void grammar_arglist(parser_t* p_parser); + +void grammar_if_stmnt(parser_t* p_parser); + +void grammar_fn_stmnt(parser_t* p_parser); + +#endif /* GRAMMAR_H */ diff --git a/source/sclpl/main.c b/source/sclpl/main.c index 860c6c7..b354ac5 100644 --- a/source/sclpl/main.c +++ b/source/sclpl/main.c @@ -1,202 +1,15 @@ -#include "scanner.h" -#include "lexer.h" -#include "opts.h" #include #include +#include "opts.h" +#include "grammar.h" -/*****************************************************************************/ -typedef struct { - lexer_t* p_lexer; - lex_tok_t* p_tok; -} parser_t; - -lex_tok_t tok_eof = { T_END_FILE, NULL, 0, 0, NULL }; - -parser_t* parser_new(char* p_prompt, FILE* input) -{ - parser_t* p_parser = (parser_t*)malloc(sizeof(parser_t)); - p_parser->p_lexer = lexer_new(p_prompt, input); - p_parser->p_tok = NULL; - return p_parser; -} - -void parser_fetch(parser_t* p_parser) -{ - p_parser->p_tok = lexer_read(p_parser->p_lexer); - if (NULL == p_parser->p_tok) - p_parser->p_tok = &tok_eof; -} - -lex_tok_t* parser_peek(parser_t* p_parser) -{ - if (NULL == p_parser->p_tok) - parser_fetch(p_parser); - return p_parser->p_tok; -} - -bool parser_eof(parser_t* p_parser) { - return (parser_peek(p_parser)->type == T_END_FILE); -} - -void parser_error(parser_t* p_parser, const char* p_text) -{ - (void)p_parser; - fprintf(stderr,"Error: %s\n",p_text); - exit(1); -} - -bool parser_accept(parser_t* p_parser, lex_tok_type_t type) -{ - bool ret = false; - if (parser_peek(p_parser)->type == type) { - p_parser->p_tok = NULL; - ret = true; - } - return ret; -} - -bool parser_accept_str(parser_t* p_parser, lex_tok_type_t type, const char* p_text) -{ - bool ret = false; - if ((parser_peek(p_parser)->type == type) && (0 == strcmp((char*)(p_parser->p_tok->value), p_text))) { - p_parser->p_tok = NULL; - ret = true; - } - return ret; -} - -bool parser_expect(parser_t* p_parser, lex_tok_type_t type) -{ - bool ret = false; - if (parser_accept(p_parser, type)) { - ret = true; - } else { - parser_error(p_parser, "Unexpected token"); - } - return ret; -} - -bool parser_expect_str(parser_t* p_parser, lex_tok_type_t type, const char* p_text) -{ - bool ret = false; - if (parser_accept_str(p_parser, type, p_text)) { - ret = true; - } else { - parser_error(p_parser, "Unexpected token"); - } - return ret; -} - -/*****************************************************************************/ -void parser_toplevel(parser_t* p_parser); -void parser_import(parser_t* p_parser); -void parser_definition(parser_t* p_parser); -void parser_expression(parser_t* p_parser); -void parser_literal(parser_t* p_parser); -void parser_arglist(parser_t* p_parser); -void parser_if_stmnt(parser_t* p_parser); -void parser_fn_stmnt(parser_t* p_parser); - -void parser_toplevel(parser_t* p_parser) -{ - if (parser_accept_str(p_parser, T_VAR, "import")) - parser_import(p_parser); - else if (parser_accept_str(p_parser, T_VAR, "def")) - parser_definition(p_parser); - else if (p_parser->p_lexer->scanner->p_input == stdin) - parser_expression(p_parser); - else - parser_error(p_parser, "Unrecognized top-level form"); -} - -void parser_import(parser_t* p_parser) -{ - parser_expect(p_parser, T_VAR); - parser_expect(p_parser, T_END); -} - -void parser_definition(parser_t* p_parser) -{ - parser_expect(p_parser,T_VAR); - if (parser_peek(p_parser)->type == T_LPAR) { - parser_fn_stmnt(p_parser); - } else { - parser_expression(p_parser); - parser_expect(p_parser,T_END); - } -} - -void parser_expression(parser_t* p_parser) -{ - if (parser_accept(p_parser, T_LPAR)) { - parser_expression(p_parser); - parser_accept(p_parser, T_RPAR); - } else if (parser_accept_str(p_parser, T_VAR, "if")) { - parser_if_stmnt(p_parser); - } else if (parser_accept_str(p_parser, T_VAR, "fn")) { - parser_fn_stmnt(p_parser); - } else if (parser_peek(p_parser)->type == T_VAR) { - parser_expect(p_parser, T_VAR); - if (parser_peek(p_parser)->type == T_LPAR) { - parser_arglist(p_parser); - } - } else { - parser_literal(p_parser); - } -} - -void parser_literal(parser_t* p_parser) -{ - switch (parser_peek(p_parser)->type) - { - case T_BOOL: - case T_CHAR: - case T_STRING: - case T_INT: - case T_FLOAT: - parser_accept(p_parser, parser_peek(p_parser)->type); - break; - - default: - parser_error(p_parser, "Not a valid expression"); - break; - } -} - -void parser_arglist(parser_t* p_parser) -{ - parser_expect(p_parser, T_LPAR); - while(parser_peek(p_parser)->type != T_RPAR) { - parser_expression(p_parser); - if(parser_peek(p_parser)->type != T_RPAR) - parser_expect(p_parser, T_COMMA); - } - parser_expect(p_parser, T_RPAR); -} - -void parser_if_stmnt(parser_t* p_parser) -{ - parser_expression(p_parser); - parser_expression(p_parser); - parser_expect_str(p_parser,T_VAR,"else"); - parser_expression(p_parser); - parser_expect(p_parser,T_END); -} - -void parser_fn_stmnt(parser_t* p_parser) -{ - parser_expect(p_parser, T_LPAR); - while(parser_peek(p_parser)->type != T_RPAR) { - parser_expect(p_parser, T_VAR); - if(parser_peek(p_parser)->type != T_RPAR) - parser_expect(p_parser, T_COMMA); - } - parser_expect(p_parser, T_RPAR); - while(parser_peek(p_parser)->type != T_END) { - parser_expression(p_parser); - } - parser_expect(p_parser, T_END); -} +/* Command Line Options + *****************************************************************************/ +OptionConfig_T Options_Config[] = { + { SHORT, (char*)"L", (char*)"scan", 0, (char*)"Output the results of lexical analysis and quit"}, + { SHORT, (char*)"P", (char*)"scan", 0, (char*)"Output the results of parsing quit"}, + { END, (char*)NULL, (char*)NULL, 0, (char*)NULL } +}; /* SCLPL Parser *****************************************************************************/ @@ -204,24 +17,19 @@ void parser_fn_stmnt(parser_t* p_parser) * Formalize grammar for parser * Paren for function application must be on same line as variable in REPL - * "end" and ';' must be equivalent * skip line on error and terminate after full program parse * skip line and print on error but do not terminate the REPL - * Phase out use of MPC - * Integrate libcds - * Integrate command line parsing */ - int main(int argc, char **argv) { - (void)argc; - (void)argv; + Result_T* results = OPTS_ParseOptions( Options_Config, argc, argv ); parser_t* p_parser = parser_new(":> ", stdin); while(!parser_eof(p_parser)) { - parser_toplevel(p_parser); + grammar_toplevel(p_parser); puts("OK."); } + (void)results; return 0; } diff --git a/source/sclpl/parser.c b/source/sclpl/parser.c new file mode 100644 index 0000000..356cd68 --- /dev/null +++ b/source/sclpl/parser.c @@ -0,0 +1,86 @@ +/** + @file parser.c + @brief See header for details + $Revision$ + $HeadURL$ + */ +#include "parser.h" +#include "vec.h" + +lex_tok_t tok_eof = { T_END_FILE, NULL, 0, 0, NULL }; + +parser_t* parser_new(char* p_prompt, FILE* input) +{ + parser_t* p_parser = (parser_t*)malloc(sizeof(parser_t)); + p_parser->p_lexer = lexer_new(p_prompt, input); + p_parser->p_tok = NULL; + p_parser->p_tok_buf = vec_new(0); + return p_parser; +} + +void parser_fetch(parser_t* p_parser) +{ + p_parser->p_tok = lexer_read(p_parser->p_lexer); + if (NULL == p_parser->p_tok) + p_parser->p_tok = &tok_eof; +} + +lex_tok_t* parser_peek(parser_t* p_parser) +{ + if (NULL == p_parser->p_tok) + parser_fetch(p_parser); + return p_parser->p_tok; +} + +bool parser_eof(parser_t* p_parser) { + return (parser_peek(p_parser)->type == T_END_FILE); +} + +void parser_error(parser_t* p_parser, const char* p_text) +{ + (void)p_parser; + fprintf(stderr,"Error: %s\n",p_text); + exit(1); +} + +bool parser_accept(parser_t* p_parser, lex_tok_type_t type) +{ + bool ret = false; + if (parser_peek(p_parser)->type == type) { + p_parser->p_tok = NULL; + ret = true; + } + return ret; +} + +bool parser_accept_str(parser_t* p_parser, lex_tok_type_t type, const char* p_text) +{ + bool ret = false; + if ((parser_peek(p_parser)->type == type) && (0 == strcmp((char*)(p_parser->p_tok->value), p_text))) { + p_parser->p_tok = NULL; + ret = true; + } + return ret; +} + +bool parser_expect(parser_t* p_parser, lex_tok_type_t type) +{ + bool ret = false; + if (parser_accept(p_parser, type)) { + ret = true; + } else { + parser_error(p_parser, "Unexpected token"); + } + return ret; +} + +bool parser_expect_str(parser_t* p_parser, lex_tok_type_t type, const char* p_text) +{ + bool ret = false; + if (parser_accept_str(p_parser, type, p_text)) { + ret = true; + } else { + parser_error(p_parser, "Unexpected token"); + } + return ret; +} diff --git a/source/sclpl/parser.h b/source/sclpl/parser.h new file mode 100644 index 0000000..b427d7f --- /dev/null +++ b/source/sclpl/parser.h @@ -0,0 +1,37 @@ +/** + @file parser.h + @brief A collection of helper functions for implementing recursive descent parsers. + $Revision$ + $HeadURL$ +*/ +#ifndef PARSER_H +#define PARSER_H + +#include "lexer.h" +#include "vec.h" + +typedef struct { + lexer_t* p_lexer; + lex_tok_t* p_tok; + vec_t* p_tok_buf; +} parser_t; + +parser_t* parser_new(char* p_prompt, FILE* input); + +void parser_fetch(parser_t* p_parser); + +lex_tok_t* parser_peek(parser_t* p_parser); + +bool parser_eof(parser_t* p_parser); + +void parser_error(parser_t* p_parser, const char* p_text); + +bool parser_accept(parser_t* p_parser, lex_tok_type_t type); + +bool parser_accept_str(parser_t* p_parser, lex_tok_type_t type, const char* p_text); + +bool parser_expect(parser_t* p_parser, lex_tok_type_t type); + +bool parser_expect_str(parser_t* p_parser, lex_tok_type_t type, const char* p_text); + +#endif /* PARSER_H */