diff --git a/lab-4/main_test.c b/lab-4/main_test.c index d82f3eb..2a8af21 100644 --- a/lab-4/main_test.c +++ b/lab-4/main_test.c @@ -16,7 +16,7 @@ UTEST_MAIN(); UTEST(parser, math) { // Must include the null character to terminate input - char string[] = "1+8/4-3;\0"; + char string[] = "COMPUTE A = (b ** 2) - (4 * a * c)\0"; YY_BUFFER_STATE buffer = yy_scan_buffer(string, sizeof(string)); yylineno = 1; @@ -28,20 +28,6 @@ UTEST(parser, math) { ASSERT_EQ(result, 0); } -UTEST(parser, missing_semi_colon) { - // Must include the null character to terminate input - char string[] = "1+8/4-3\0"; - YY_BUFFER_STATE buffer = yy_scan_buffer(string, sizeof(string)); - - yylineno = 1; - int result = yyparse(); - - yy_delete_buffer(buffer); - - // Assert the result to test correctness - ASSERT_EQ(result, 1); -} - UTEST(parser, hello) { // Read sample file as input yyin = fopen("samples/hello-world.cbl", "r"); @@ -71,7 +57,7 @@ UTEST(parser, print) { UTEST(parser, branching) { // Must include the null character to terminate input - char string[] = "IF A > B THEN DISPLAY 'A is greater than B' ELSE DISPLAY 'B is greater than A'\0"; + char string[] = "IF A > B DISPLAY 'A is greater than B' ELSE DISPLAY 'B is greater than A'\0"; YY_BUFFER_STATE buffer = yy_scan_buffer(string, sizeof(string)); yylineno = 1; @@ -81,10 +67,23 @@ UTEST(parser, branching) { // Assert the result to test correctness ASSERT_EQ(result, 0); -} +} UTEST(parser, looping) { - char string[] = "PERFORM VARYING I FROM 1 BY 1 UNTIL I > 10 MOVE I TO A(I)\0"; + char string[] = "PERFORM VARYING I FROM 1 BY 1 UNTIL I > 10\0"; + YY_BUFFER_STATE buffer = yy_scan_buffer(string, sizeof(string)); + + yylineno = 1; + int result = yyparse(); + + yy_delete_buffer(buffer); + + // Assert the result to test correctness + ASSERT_EQ(result, 0); +} + +UTEST(parser, assignment) { + char string[] = "MOVE I TO A(I) MOVE 1 TO I COMPUTE discriminant = (b ** 2) - (4 * a * c)\0"; YY_BUFFER_STATE buffer = yy_scan_buffer(string, sizeof(string)); yylineno = 1; @@ -121,17 +120,3 @@ UTEST(parser, quadratic) { // Assert the result to test correctness ASSERT_EQ(result, 0); } - -UTEST(parser, boolean) { - // Must include the null character to terminate input - char string[] = "IF A > B THEN Var = TRUE ELSE Var = FALSE\0"; - YY_BUFFER_STATE buffer = yy_scan_buffer(string, sizeof(string)); - - yylineno = 1; - int result = yyparse(); - - yy_delete_buffer(buffer); - - // Assert the result to test correctness - ASSERT_EQ(result, 0); -} diff --git a/lab-4/parser.bison b/lab-4/parser.bison index 4e21a07..c0c71ca 100644 --- a/lab-4/parser.bison +++ b/lab-4/parser.bison @@ -51,7 +51,6 @@ int yylex(); %token TOKEN_LEFT_PARENTHESIS %token TOKEN_RIGHT_PARENTHESIS %token TOKEN_DOT -%token TOKEN_COMMENT %token TOKEN_ADD %token TOKEN_SUB %token TOKEN_MULTIPLY @@ -65,7 +64,9 @@ int yylex(); %% file : statements -statements : statements statement +statements : statement_list + ; +statement_list : statement_list statement | statement ; statement : section @@ -85,22 +86,18 @@ type : TOKEN_KEYWORD_IDENTIFICATION | TOKEN_STOP | TOKEN_KEYWORD_DATA ; -simple_stmt : cbl_function - | cbl_function param - | cbl_function assignment_stmt - | cbl_function param assignment_stmt - | cbl_function TOKEN_IDENT assignment_stmt +simple_stmt : cbl_func_stmt | if_branch + | perform_stmt ; -expression : op_parms - | bool - ; -bool : op_parms TOKEN_EQUAL op_parms +cbl_func_stmt : cbl_function + | cbl_function op_parms + | cbl_function assignment_stmt + | cbl_function op_parms assignment_stmt ; assignment_stmt : TOKEN_EQUAL ext_function | TOKEN_EQUAL function - | TOKEN_KEYWORD_TO TOKEN_IDENT - | TOKEN_KEYWORD_TO TOKEN_IDENT categry_contain + | TOKEN_KEYWORD_TO op_parms ; op_parms : op_parms TOKEN_ADD op_parms | op_parms TOKEN_SUB op_parms @@ -109,14 +106,16 @@ op_parms : op_parms TOKEN_ADD op_parms | op_parms TOKEN_EXPONENTIAL op_parms | op_parms TOKEN_LESS_THAN op_parms | op_parms TOKEN_GREATER_THAN op_parms + | op_parms TOKEN_EQUAL op_parms | TOKEN_SUB op_parms | TOKEN_LEFT_PARENTHESIS op_parms TOKEN_RIGHT_PARENTHESIS - | TOKEN_IDENT - | TOKEN_INTEGER + | expr + | op_parms op_parms ; -param : TOKEN_IDENT +expr : TOKEN_IDENT + | TOKEN_INTEGER | TOKEN_STRING - | param param + | TOKEN_SPACE ; function : op_parms ; @@ -127,11 +126,14 @@ cbl_function : TOKEN_DISPLAY | TOKEN_KEYWORD_COMPUTE | TOKEN_PERFORM ; -if_branch : TOKEN_IF expression - | TOKEN_ELSE_IF expression +if_branch : TOKEN_IF op_parms + | TOKEN_ELSE_IF op_parms | TOKEN_ELSE statement | TOKEN_END_IF ; +perform_stmt : TOKEN_PERFORM TOKEN_VARYING TOKEN_IDENT TOKEN_KEYWORD_FROM TOKEN_INTEGER TOKEN_KEYWORD_BY TOKEN_INTEGER TOKEN_UNTIL op_parms + | TOKEN_END_PERFORM + ; data_space : TOKEN_WORKING_STORAGE | TOKEN_KEYWORD_SECTION | TOKEN_DOT @@ -142,9 +144,10 @@ data_category : TOKEN_ALPHANUMERIC | TOKEN_IMPLIED_DECIMAL ; categry_contain : TOKEN_LEFT_PARENTHESIS TOKEN_INTEGER TOKEN_RIGHT_PARENTHESIS + | TOKEN_LEFT_PARENTHESIS TOKEN_IDENT TOKEN_RIGHT_PARENTHESIS ; -complete_category: complete_category complete_category - | data_category categry_contain +complete_category: data_category categry_contain + | data_category categry_contain complete_category ; data_clause : TOKEN_COMPUTATION_LEVEL_0 | TOKEN_COMPUTATION_LEVEL_1 @@ -158,15 +161,18 @@ full_data_clause: data_clause data_clause ; simple_decl : TOKEN_INTEGER TOKEN_IDENT TOKEN_DOT ; -full_decl : TOKEN_INTEGER TOKEN_IDENT TOKEN_PICTURE complete_category TOKEN_DOT - | TOKEN_INTEGER TOKEN_IDENT TOKEN_PICTURE complete_category full_data_clause TOKEN_DOT - | TOKEN_INTEGER TOKEN_IDENT TOKEN_PICTURE complete_category full_data_clause TOKEN_INTEGER TOKEN_DOT +complex_decl : TOKEN_INTEGER TOKEN_IDENT TOKEN_PICTURE category_spec TOKEN_DOT + ; +category_spec : complete_category + | complete_category data_clauses + ; +data_clauses : full_data_clause + | full_data_clause TOKEN_INTEGER ; data_declaration: simple_decl - | full_decl + | complex_decl ; - %% void yyerror(const char* msg) { fprintf(stderr, "Error | Line: %d\n%s\n",yylineno,msg); diff --git a/lab-4/samples/only-variables.cbl b/lab-4/samples/only-variables.cbl index 41685e8..1a900a5 100644 --- a/lab-4/samples/only-variables.cbl +++ b/lab-4/samples/only-variables.cbl @@ -4,7 +4,7 @@ DATA DIVISION. WORKING-STORAGE SECTION. 01 WS-SORT-AREA. 05 WS-SORT-TABLE. - 10 WS-SORT-ROW PIC X(10) OCCURS 100. + 10 WS-SORT-ROW PIC X(10) OCCURS 100. 05 WS-TEMP-ROW PIC X(10). 05 WS-ROW-MAX PIC S9(4) COMP VALUE 100. 05 WS-SORT-MAX PIC S9(4) COMP. diff --git a/lab-4/scanner.flex b/lab-4/scanner.flex index 5c97694..4b7a148 100644 --- a/lab-4/scanner.flex +++ b/lab-4/scanner.flex @@ -6,7 +6,7 @@ DIGIT [0-9]+ %% (" "|\t|\n) /* skip whitespace */ -\*>\ ?.* { return TOKEN_COMMENT; } +\*>\ ?.* IDENTIFICATION { return TOKEN_KEYWORD_IDENTIFICATION; } DIVISION { return TOKEN_KEYWORD_DIVISION; } PROGRAM-ID { return TOKEN_PROGRAM_ID; } diff --git a/lab-4/token.h b/lab-4/token.h deleted file mode 100644 index ca9bbfb..0000000 --- a/lab-4/token.h +++ /dev/null @@ -1,127 +0,0 @@ -/* A Bison parser, made by GNU Bison 3.8.2. */ - -/* Bison interface for Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, - Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - -/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, - especially those whose name start with YY_ or yy_. They are - private implementation details that can be changed or removed. */ - -#ifndef YY_YY_TOKEN_H_INCLUDED -# define YY_YY_TOKEN_H_INCLUDED -/* Debug traces. */ -#ifndef YYDEBUG -# define YYDEBUG 1 -#endif -#if YYDEBUG -extern int yydebug; -#endif - -/* Token kinds. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - enum yytokentype - { - YYEMPTY = -2, - YYEOF = 0, /* "end of file" */ - YYerror = 256, /* error */ - YYUNDEF = 257, /* "invalid token" */ - TOKEN_EOF = 258, /* TOKEN_EOF */ - TOKEN_KEYWORD_IDENTIFICATION = 259, /* TOKEN_KEYWORD_IDENTIFICATION */ - TOKEN_KEYWORD_DIVISION = 260, /* TOKEN_KEYWORD_DIVISION */ - TOKEN_KEYWORD_DATA = 261, /* TOKEN_KEYWORD_DATA */ - TOKEN_KEYWORD_SECTION = 262, /* TOKEN_KEYWORD_SECTION */ - TOKEN_PROGRAM_ID = 263, /* TOKEN_PROGRAM_ID */ - TOKEN_WORKING_STORAGE = 264, /* TOKEN_WORKING_STORAGE */ - TOKEN_PROCEDURE = 265, /* TOKEN_PROCEDURE */ - TOKEN_STOP = 266, /* TOKEN_STOP */ - TOKEN_RUN = 267, /* TOKEN_RUN */ - TOKEN_MOVE = 268, /* TOKEN_MOVE */ - TOKEN_KEYWORD_TO = 269, /* TOKEN_KEYWORD_TO */ - TOKEN_PERFORM = 270, /* TOKEN_PERFORM */ - TOKEN_VARYING = 271, /* TOKEN_VARYING */ - TOKEN_KEYWORD_FROM = 272, /* TOKEN_KEYWORD_FROM */ - TOKEN_KEYWORD_BY = 273, /* TOKEN_KEYWORD_BY */ - TOKEN_UNTIL = 274, /* TOKEN_UNTIL */ - TOKEN_END_PERFORM = 275, /* TOKEN_END_PERFORM */ - TOKEN_IF = 276, /* TOKEN_IF */ - TOKEN_ELSE = 277, /* TOKEN_ELSE */ - TOKEN_ELSE_IF = 278, /* TOKEN_ELSE_IF */ - TOKEN_END_IF = 279, /* TOKEN_END_IF */ - TOKEN_SPACE = 280, /* TOKEN_SPACE */ - TOKEN_KEYWORD_OCCURS = 281, /* TOKEN_KEYWORD_OCCURS */ - TOKEN_KEYWORD_VALUE = 282, /* TOKEN_KEYWORD_VALUE */ - TOKEN_KEYWORD_COMPUTE = 283, /* TOKEN_KEYWORD_COMPUTE */ - TOKEN_KEYWORD_FUNCTION = 284, /* TOKEN_KEYWORD_FUNCTION */ - TOKEN_IDENT = 285, /* TOKEN_IDENT */ - TOKEN_STRING = 286, /* TOKEN_STRING */ - TOKEN_INTEGER = 287, /* TOKEN_INTEGER */ - TOKEN_PICTURE = 288, /* TOKEN_PICTURE */ - TOKEN_ALPHANUMERIC = 289, /* TOKEN_ALPHANUMERIC */ - TOKEN_NUMERIC = 290, /* TOKEN_NUMERIC */ - TOKEN_SIGNED_NUMERIC = 291, /* TOKEN_SIGNED_NUMERIC */ - TOKEN_IMPLIED_DECIMAL = 292, /* TOKEN_IMPLIED_DECIMAL */ - TOKEN_COMPUTATION_LEVEL_0 = 293, /* TOKEN_COMPUTATION_LEVEL_0 */ - TOKEN_COMPUTATION_LEVEL_1 = 294, /* TOKEN_COMPUTATION_LEVEL_1 */ - TOKEN_COMPUTATION_LEVEL_2 = 295, /* TOKEN_COMPUTATION_LEVEL_2 */ - TOKEN_COMPUTATION_LEVEL_3 = 296, /* TOKEN_COMPUTATION_LEVEL_3 */ - TOKEN_LEFT_PARENTHESIS = 297, /* TOKEN_LEFT_PARENTHESIS */ - TOKEN_RIGHT_PARENTHESIS = 298, /* TOKEN_RIGHT_PARENTHESIS */ - TOKEN_DOT = 299, /* TOKEN_DOT */ - TOKEN_COMMENT = 300, /* TOKEN_COMMENT */ - TOKEN_ADD = 301, /* TOKEN_ADD */ - TOKEN_SUB = 302, /* TOKEN_SUB */ - TOKEN_MULTIPLY = 303, /* TOKEN_MULTIPLY */ - TOKEN_DIVIDE = 304, /* TOKEN_DIVIDE */ - TOKEN_EQUAL = 305, /* TOKEN_EQUAL */ - TOKEN_GREATER_THAN = 306, /* TOKEN_GREATER_THAN */ - TOKEN_LESS_THAN = 307, /* TOKEN_LESS_THAN */ - TOKEN_EXPONENTIAL = 308, /* TOKEN_EXPONENTIAL */ - TOKEN_DISPLAY = 309 /* TOKEN_DISPLAY */ - }; - typedef enum yytokentype yytoken_kind_t; -#endif - -/* Value type. */ -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef int YYSTYPE; -# define YYSTYPE_IS_TRIVIAL 1 -# define YYSTYPE_IS_DECLARED 1 -#endif - - -extern YYSTYPE yylval; - - -int yyparse (void); - - -#endif /* !YY_YY_TOKEN_H_INCLUDED */ diff --git a/lab-5/Makefile b/lab-5/Makefile index dfc7723..0361623 100644 --- a/lab-5/Makefile +++ b/lab-5/Makefile @@ -20,7 +20,7 @@ scanner.c: scanner.flex parser.h flex -oscanner.c scanner.flex parser.c parser.h: parser.bison - bison --defines=parser.h --output=parser.c -v parser.bison -Wconflicts-sr -Wcounterexamples + bison --defines=parser.h --output=parser.c -v parser.bison # clean causes all intermediate files to be deleted. diff --git a/lab-5/parser.bison b/lab-5/parser.bison index 0f901ba..e536a2c 100644 --- a/lab-5/parser.bison +++ b/lab-5/parser.bison @@ -1,189 +1,206 @@ - -/* -Declare token types at the top of the bison file, -causing them to be automatically generated in parser.tab.h -for use by scanner.c. -*/ - -%debug -%define parse.error detailed - -%token TOKEN_ASSIGNMENT -%token TOKEN_COMMA -%token TOKEN_DIV -%token TOKEN_EQUAL_EQUAL -%token TOKEN_GREATER_THAN -%token TOKEN_GREATER_THAN_OR_EQUAL -%token TOKEN_ID -%token TOKEN_INT -%token TOKEN_INTEGER -%token TOKEN_KEYWORD_ENDIF -%token TOKEN_KEYWORD_IF -%token TOKEN_KEYWORD_PRINT -%token TOKEN_KEYWORD_THEN -%token TOKEN_LBRACKET -%token TOKEN_LESS_THAN -%token TOKEN_LESS_THAN_OR_EQUAL -%token TOKEN_LPAREN -%token TOKEN_MINUS -%token TOKEN_MUL -%token TOKEN_NOT_EQUAL -%token TOKEN_PLUS -%token TOKEN_RBRACKET -%token TOKEN_RPAREN -%token TOKEN_SEMI - -%union { - struct stmt *stmt; - struct expr *expr; - struct decl *decl; -}; - -%type program statement_list statement print_statement assignment_statement if_statement block -%type expr term factor name sum array_subscript star_expr -%type declaration - %{ #define YYDEBUG 1 +#include #include #include #include #include "expr.h" +/* +YYSTYPE is the lexical value returned by each rule in a bison grammar. +By default, it is an integer. In this example, we are returning a pointer to an expression. +*/ + +#define YYSTYPE struct expr * /* Clunky: Manually declare the interface to the scanner generated by flex. */ -extern int yylineno; extern char *yytext; extern int yylex(); -extern void yyerror(const char*); +extern int yylineno; +void yyerror(const char*); + /* Clunky: Keep the final result of the parse in a global variable, so that it can be retrieved by main(). */ -struct stmt * parser_result = 0; - +struct expr * parser_result = 0; %} -%% +%debug +%define parse.error detailed -/* Here is the grammar: program is the start symbol. */ -program : statement_list - { parser_result = $1; return 0; } - ; +%token TOKEN_EOF +%token TOKEN_KEYWORD_IDENTIFICATION +%token TOKEN_KEYWORD_DIVISION +%token TOKEN_KEYWORD_DATA +%token TOKEN_KEYWORD_SECTION +%token TOKEN_PROGRAM_ID +%token TOKEN_WORKING_STORAGE +%token TOKEN_PROCEDURE +%token TOKEN_STOP +%token TOKEN_RUN +%token TOKEN_MOVE +%token TOKEN_KEYWORD_TO +%token TOKEN_PERFORM +%token TOKEN_VARYING +%token TOKEN_KEYWORD_FROM +%token TOKEN_KEYWORD_BY +%token TOKEN_UNTIL +%token TOKEN_END_PERFORM +%token TOKEN_IF +%token TOKEN_ELSE_IF +%token TOKEN_ELSE +%token TOKEN_END_IF +%token TOKEN_SPACE +%token TOKEN_KEYWORD_OCCURS +%token TOKEN_KEYWORD_VALUE +%token TOKEN_KEYWORD_COMPUTE +%token TOKEN_KEYWORD_FUNCTION +%token TOKEN_IDENT +%token TOKEN_STRING +%token TOKEN_INTEGER +%token TOKEN_PICTURE +%token TOKEN_ALPHANUMERIC +%token TOKEN_NUMERIC +%token TOKEN_SIGNED_NUMERIC +%token TOKEN_IMPLIED_DECIMAL +%token TOKEN_COMPUTATION_LEVEL_0 +%token TOKEN_COMPUTATION_LEVEL_1 +%token TOKEN_COMPUTATION_LEVEL_2 +%token TOKEN_COMPUTATION_LEVEL_3 +%token TOKEN_LEFT_PARENTHESIS +%token TOKEN_RIGHT_PARENTHESIS +%token TOKEN_DOT +%token TOKEN_ADD +%token TOKEN_SUB +%token TOKEN_MULTIPLY +%token TOKEN_DIVIDE +%token TOKEN_EQUAL +%token TOKEN_GREATER_THAN +%token TOKEN_LESS_THAN +%token TOKEN_EXPONENTIAL +%token TOKEN_DISPLAY -statement_list : statement - { $$ = $1; } - | statement statement_list - { $$ = $1; $1->next = $2; } - ; - -block : statement - { $$ = $1; } - | statement block - { $$ = $1; $1->next = $2; } - ; - -statement : assignment_statement TOKEN_SEMI - { $$ = $1; } - | print_statement TOKEN_SEMI - { $$ = $1; } - | if_statement - { $$ = $1; } - ; - -assignment_statement : declaration - { $$ = stmt_create(STMT_DECL,$1,0,0,0,0,0,0); } - ; - -print_statement : TOKEN_KEYWORD_PRINT expr - { $$ = stmt_create(STMT_PRINT,0,0,$2,0,0,0,0); } - ; - -if_statement : TOKEN_KEYWORD_IF expr TOKEN_KEYWORD_THEN block TOKEN_KEYWORD_ENDIF - { $$ = stmt_create(STMT_IF,0,0,$2,0,$4,0,0); } - ; - -declaration : name TOKEN_ASSIGNMENT expr - { $$ = decl_create($1,0,$3,0,0); } - | array_subscript TOKEN_ASSIGNMENT expr - { $$ = decl_create($1,0,$3,0,0); } - ; - -name : TOKEN_ID - { $$ = expr_create_name(yytext); } - ; - -array_subscript : name TOKEN_LBRACKET expr TOKEN_RBRACKET - { $$ = expr_create(EXPR_SUBSCRIPT,$1,$3); } - ; - -star_expr : expr - { $$ = expr_create(EXPR_ARRAY,$1,0); } - | expr TOKEN_COMMA star_expr - { $$ = expr_create(EXPR_ARRAY,$1,$3); } - ; - -expr : sum TOKEN_LESS_THAN sum - { $$ = expr_create(EXPR_LESS_THAN,$1,$3); } - | sum TOKEN_LESS_THAN_OR_EQUAL sum - { $$ = expr_create(EXPR_LESS_THAN_OR_EQUAL,$1,$3); } - | sum TOKEN_GREATER_THAN sum - { $$ = expr_create(EXPR_GREATER_THAN,$1,$3); } - | sum TOKEN_GREATER_THAN_OR_EQUAL sum - { $$ = expr_create(EXPR_GREATER_THAN_OR_EQUAL,$1,$3); } - | sum TOKEN_EQUAL_EQUAL sum - { $$ = expr_create(EXPR_EQUAL_EQUAL,$1,$3); } - | sum TOKEN_NOT_EQUAL sum - { $$ = expr_create(EXPR_NOT_EQUAL,$1,$3); } - | sum - { $$ = $1; } - ; - -sum : sum TOKEN_PLUS term - { $$ = expr_create(EXPR_ADD,$1,$3); } - | sum TOKEN_MINUS term - { $$ = expr_create(EXPR_SUBTRACT,$1,$3); } - | term - { $$ = $1; } - ; - -term : term TOKEN_MUL factor - { $$ = expr_create(EXPR_MULTIPLY,$1,$3); } - | term TOKEN_DIV factor - { $$ = expr_create(EXPR_DIVIDE,$1,$3); } - | factor - { $$ = $1; } - ; - -factor : TOKEN_LPAREN expr TOKEN_RPAREN - { $$ = $2; } - | TOKEN_MINUS factor - { $$ = expr_create(EXPR_SUBTRACT,expr_create_integer_literal(0),$2); } - | TOKEN_INT - { $$ = expr_create_integer_literal(atoi(yytext)); } - | TOKEN_LBRACKET star_expr TOKEN_RBRACKET - { $$ = $2; } - | array_subscript - { $$ = $1; } - | name - { $$ = $1; } - ; %% +file : statements +statements : statement_list + ; +statement_list : statement_list statement + | statement + ; +statement : section + | sect_data + | simple_stmt + | data_space + | data_declaration + ; + +section : type TOKEN_KEYWORD_DIVISION TOKEN_DOT + | type TOKEN_RUN TOKEN_DOT + ; +sect_data : TOKEN_PROGRAM_ID TOKEN_DOT TOKEN_IDENT TOKEN_DOT + ; +type : TOKEN_KEYWORD_IDENTIFICATION + | TOKEN_PROCEDURE + | TOKEN_STOP + | TOKEN_KEYWORD_DATA + ; +simple_stmt : cbl_func_stmt + | if_branch + | perform_stmt + ; +cbl_func_stmt : cbl_function + | cbl_function op_parms + | cbl_function assignment_stmt + | cbl_function op_parms assignment_stmt + ; +assignment_stmt : TOKEN_EQUAL ext_function + | TOKEN_EQUAL function + | TOKEN_KEYWORD_TO op_parms + ; +op_parms : op_parms TOKEN_ADD op_parms + | op_parms TOKEN_SUB op_parms + | op_parms TOKEN_MULTIPLY op_parms + | op_parms TOKEN_DIVIDE op_parms + | op_parms TOKEN_EXPONENTIAL op_parms + | op_parms TOKEN_LESS_THAN op_parms + | op_parms TOKEN_GREATER_THAN op_parms + | op_parms TOKEN_EQUAL op_parms + | TOKEN_SUB op_parms + | TOKEN_LEFT_PARENTHESIS op_parms TOKEN_RIGHT_PARENTHESIS + | expr + | op_parms op_parms + ; +expr : TOKEN_IDENT + | TOKEN_INTEGER + | TOKEN_STRING + | TOKEN_SPACE + ; +function : op_parms + ; +ext_function : TOKEN_KEYWORD_FUNCTION TOKEN_IDENT TOKEN_LEFT_PARENTHESIS TOKEN_IDENT TOKEN_RIGHT_PARENTHESIS + ; +cbl_function : TOKEN_DISPLAY + | TOKEN_MOVE + | TOKEN_KEYWORD_COMPUTE + | TOKEN_PERFORM + ; +if_branch : TOKEN_IF op_parms + | TOKEN_ELSE_IF op_parms + | TOKEN_ELSE statement + | TOKEN_END_IF + ; +perform_stmt : TOKEN_PERFORM TOKEN_VARYING TOKEN_IDENT TOKEN_KEYWORD_FROM TOKEN_INTEGER TOKEN_KEYWORD_BY TOKEN_INTEGER TOKEN_UNTIL op_parms + | TOKEN_END_PERFORM + ; +data_space : TOKEN_WORKING_STORAGE + | TOKEN_KEYWORD_SECTION + | TOKEN_DOT + ; +data_category : TOKEN_ALPHANUMERIC + | TOKEN_NUMERIC + | TOKEN_SIGNED_NUMERIC + | TOKEN_IMPLIED_DECIMAL + ; +categry_contain : TOKEN_LEFT_PARENTHESIS TOKEN_INTEGER TOKEN_RIGHT_PARENTHESIS + | TOKEN_LEFT_PARENTHESIS TOKEN_IDENT TOKEN_RIGHT_PARENTHESIS + ; +complete_category: data_category categry_contain + | data_category categry_contain complete_category + ; +data_clause : TOKEN_COMPUTATION_LEVEL_0 + | TOKEN_COMPUTATION_LEVEL_1 + | TOKEN_COMPUTATION_LEVEL_2 + | TOKEN_COMPUTATION_LEVEL_3 + | TOKEN_KEYWORD_VALUE + | TOKEN_KEYWORD_OCCURS + ; +full_data_clause: data_clause data_clause + | data_clause + ; +simple_decl : TOKEN_INTEGER TOKEN_IDENT TOKEN_DOT + ; +complex_decl : TOKEN_INTEGER TOKEN_IDENT TOKEN_PICTURE category_spec TOKEN_DOT + ; +category_spec : complete_category + | complete_category data_clauses + ; +data_clauses : full_data_clause + | full_data_clause TOKEN_INTEGER + ; +data_declaration: simple_decl + | complex_decl + ; -/* -This function will be called by bison if the parse should -encounter an error. In principle, "str" will contain something -useful. In practice, it often does not. -*/ - +%% void yyerror(const char* msg) { - fprintf(stderr, "Error | Line: %d\n%s\n", yylineno, msg); + fprintf(stderr, "Error | Line: %d\n%s\n",yylineno,msg); } diff --git a/lab-5/samples/array_assignment.c b/lab-5/samples/array_assignment.c deleted file mode 100644 index cce2d38..0000000 --- a/lab-5/samples/array_assignment.c +++ /dev/null @@ -1 +0,0 @@ -a = [ 4, 8, 12 ]; diff --git a/lab-5/samples/array_read.c b/lab-5/samples/array_read.c deleted file mode 100644 index db30710..0000000 --- a/lab-5/samples/array_read.c +++ /dev/null @@ -1,2 +0,0 @@ -a = [ 3, 5 ]; -print a[0]; \ No newline at end of file diff --git a/lab-5/samples/array_write.c b/lab-5/samples/array_write.c deleted file mode 100644 index 4f81214..0000000 --- a/lab-5/samples/array_write.c +++ /dev/null @@ -1,4 +0,0 @@ -a = [ 3, 5, 7, 9, 11]; -print a[1]; -a[1] = 6; -print a[1]; diff --git a/lab-5/samples/assignment_statement.c b/lab-5/samples/assignment_statement.c deleted file mode 100644 index a5a2277..0000000 --- a/lab-5/samples/assignment_statement.c +++ /dev/null @@ -1 +0,0 @@ -a = 5; \ No newline at end of file diff --git a/lab-5/samples/hello-world.cbl b/lab-5/samples/hello-world.cbl new file mode 100644 index 0000000..737f19e --- /dev/null +++ b/lab-5/samples/hello-world.cbl @@ -0,0 +1,5 @@ +IDENTIFICATION DIVISION. +PROGRAM-ID. HELLO-WORLD. +PROCEDURE DIVISION. + DISPLAY 'Hello World!' +STOP RUN. diff --git a/lab-5/samples/multiple_statements.c b/lab-5/samples/multiple_statements.c deleted file mode 100644 index b31de4e..0000000 --- a/lab-5/samples/multiple_statements.c +++ /dev/null @@ -1,2 +0,0 @@ -print 5; -print 6; diff --git a/lab-5/samples/multiple_statements_evaluate.txt b/lab-5/samples/multiple_statements_evaluate.txt deleted file mode 100644 index 2ebc651..0000000 --- a/lab-5/samples/multiple_statements_evaluate.txt +++ /dev/null @@ -1 +0,0 @@ -56 \ No newline at end of file diff --git a/lab-5/samples/multiple_statements_print.txt b/lab-5/samples/multiple_statements_print.txt deleted file mode 100644 index b31de4e..0000000 --- a/lab-5/samples/multiple_statements_print.txt +++ /dev/null @@ -1,2 +0,0 @@ -print 5; -print 6; diff --git a/lab-5/samples/only-variables.cbl b/lab-5/samples/only-variables.cbl new file mode 100644 index 0000000..1a900a5 --- /dev/null +++ b/lab-5/samples/only-variables.cbl @@ -0,0 +1,24 @@ +IDENTIFICATION DIVISION. +PROGRAM-ID. variables. +DATA DIVISION. +WORKING-STORAGE SECTION. + 01 WS-SORT-AREA. + 05 WS-SORT-TABLE. + 10 WS-SORT-ROW PIC X(10) OCCURS 100. + 05 WS-TEMP-ROW PIC X(10). + 05 WS-ROW-MAX PIC S9(4) COMP VALUE 100. + 05 WS-SORT-MAX PIC S9(4) COMP. + 05 WS-I PIC S9(4) COMP. + 05 WS-J PIC S9(4) COMP. + 05 WS-INDEX PIC S9(4) COMP. + 77 a PIC S9(5)V9(5) COMP-3 VALUE 1. + 77 b PIC S9(5)V9(5) COMP-3 VALUE 5. + 77 c PIC S9(5)V9(5) COMP-3 VALUE 6. + 77 discriminant PIC S9(5)V9(5) COMP-3. + 77 root1 PIC S9(5)V9(5) COMP-3. + 77 root2 PIC S9(5)V9(5) COMP-3. + 77 square-root-discriminant PIC S9(5)V9(5) COMP-3. + +PROCEDURE DIVISION. + DISPLAY 'Hello World!' + STOP RUN. \ No newline at end of file diff --git a/lab-5/samples/print_if_equal.c b/lab-5/samples/print_if_equal.c deleted file mode 100644 index e4a42e4..0000000 --- a/lab-5/samples/print_if_equal.c +++ /dev/null @@ -1,6 +0,0 @@ -if 3==3 then - print 3; -endif -if 3==4 then - print 4; -endif diff --git a/lab-5/samples/print_if_false.c b/lab-5/samples/print_if_false.c deleted file mode 100644 index 5340a03..0000000 --- a/lab-5/samples/print_if_false.c +++ /dev/null @@ -1,5 +0,0 @@ -if 0 then - print 5; - print 3; - print 1; -endif diff --git a/lab-5/samples/print_if_true.c b/lab-5/samples/print_if_true.c deleted file mode 100644 index 7848347..0000000 --- a/lab-5/samples/print_if_true.c +++ /dev/null @@ -1,5 +0,0 @@ -if 1 then - print 5; - print 3; - print 1; -endif diff --git a/lab-5/samples/print_statement.c b/lab-5/samples/print_statement.c deleted file mode 100644 index 1748ba7..0000000 --- a/lab-5/samples/print_statement.c +++ /dev/null @@ -1 +0,0 @@ -print 5; diff --git a/lab-5/samples/print_variable.c b/lab-5/samples/print_variable.c deleted file mode 100644 index 28aae29..0000000 --- a/lab-5/samples/print_variable.c +++ /dev/null @@ -1,2 +0,0 @@ -a = 4 + 4; -print a; diff --git a/lab-5/samples/program.c b/lab-5/samples/program.c deleted file mode 100644 index f1f084a..0000000 --- a/lab-5/samples/program.c +++ /dev/null @@ -1,2 +0,0 @@ -a=(101*20)+4; -print(a); diff --git a/lab-5/samples/program_evaluate.txt b/lab-5/samples/program_evaluate.txt deleted file mode 100644 index dba6080..0000000 --- a/lab-5/samples/program_evaluate.txt +++ /dev/null @@ -1 +0,0 @@ -2024 \ No newline at end of file diff --git a/lab-5/samples/program_print.txt b/lab-5/samples/program_print.txt deleted file mode 100644 index 185dd2d..0000000 --- a/lab-5/samples/program_print.txt +++ /dev/null @@ -1,2 +0,0 @@ -a = ((101*20)+4); -print(a); diff --git a/lab-5/samples/quadratic-snippet.cbl b/lab-5/samples/quadratic-snippet.cbl new file mode 100644 index 0000000..ab76e40 --- /dev/null +++ b/lab-5/samples/quadratic-snippet.cbl @@ -0,0 +1,35 @@ + *> Code altered from https://www.quora.com/What-is-a-COBOL-program-that-will-solve-a-quadratic-equation + *> Program finds the roots to a simple quadratic equation + + IDENTIFICATION DIVISION. + PROGRAM-ID. QuadraticSolver. + DATA DIVISION. + WORKING-STORAGE SECTION. + 77 a PIC S9(5)V9(5) COMP-3 VALUE 1. + 77 b PIC S9(5)V9(5) COMP-3 VALUE 5. + 77 c PIC S9(5)V9(5) COMP-3 VALUE 6. + 77 discriminant PIC S9(5)V9(5) COMP-3. + 77 root1 PIC S9(5)V9(5) COMP-3. + 77 root2 PIC S9(5)V9(5) COMP-3. + 77 square-root-discriminant PIC S9(5)V9(5) COMP-3. + + PROCEDURE DIVISION. *> program begins here + DISPLAY "EQUATION: (1x^2) + 5x + 6 = 0" + COMPUTE discriminant = (b ** 2) - (4 * a * c) + + IF discriminant > 0 + COMPUTE square-root-discriminant = FUNCTION SQRT(discriminant) + COMPUTE root1 = (-b + square-root-discriminant) / (2 * a) + COMPUTE root2 = (-b - square-root-discriminant) / (2 * a) + DISPLAY "The equation has two distinct real roots: " + DISPLAY "Root 1: " root1 + DISPLAY "Root 2: " root2 + + ELSE IF discriminant = 0 + COMPUTE root1 = -b / (2 * a) + DISPLAY "The equation has one real root: " + DISPLAY "Root: " root1 + ELSE + DISPLAY "The equation has no real roots." + + STOP RUN. diff --git a/lab-5/samples/sorting-snippet.cbl b/lab-5/samples/sorting-snippet.cbl new file mode 100644 index 0000000..8324e47 --- /dev/null +++ b/lab-5/samples/sorting-snippet.cbl @@ -0,0 +1,55 @@ +IDENTIFICATION DIVISION. +PROGRAM-ID. sorting. +DATA DIVISION. +WORKING-STORAGE SECTION. + 01 WS-SORT-AREA. + 05 WS-SORT-TABLE. + 10 WS-SORT-ROW PIC X(10) OCCURS 100. + 05 WS-TEMP-ROW PIC X(10). + 05 WS-ROW-MAX PIC S9(4) COMP VALUE 100. + 05 WS-SORT-MAX PIC S9(4) COMP. + 05 WS-I PIC S9(4) COMP. + 05 WS-J PIC S9(4) COMP. + 05 WS-INDEX PIC S9(4) COMP. + +PROCEDURE DIVISION. +*> Initialize test data + MOVE "30" TO WS-SORT-ROW(1) + MOVE "10" TO WS-SORT-ROW(2) + MOVE "50" TO WS-SORT-ROW(3) + MOVE "20" TO WS-SORT-ROW(4) + MOVE "40" TO WS-SORT-ROW(5) + MOVE 5 TO WS-SORT-MAX + +*> * Display original array + DISPLAY "Original Array Contents:" + DISPLAY "---------------------" + PERFORM VARYING WS-INDEX FROM 1 BY 1 + UNTIL WS-INDEX > WS-SORT-MAX + DISPLAY "Element " WS-INDEX ": " WS-SORT-ROW(WS-INDEX) + END-PERFORM + DISPLAY SPACE + +*> * Simplified bubble sort + PERFORM VARYING WS-I FROM 1 BY 1 + UNTIL WS-I > WS-SORT-MAX - 1 + PERFORM VARYING WS-J FROM 1 BY 1 + UNTIL WS-J > WS-SORT-MAX - WS-I + IF WS-SORT-ROW(WS-J) > WS-SORT-ROW(WS-J + 1) + MOVE WS-SORT-ROW(WS-J) TO WS-TEMP-ROW + MOVE WS-SORT-ROW(WS-J + 1) TO WS-SORT-ROW(WS-J) + MOVE WS-TEMP-ROW TO WS-SORT-ROW(WS-J + 1) + END-IF + END-PERFORM + END-PERFORM + +*> * Display sorted array + DISPLAY "Sorted Array Contents:" + DISPLAY "--------------------" + PERFORM VARYING WS-INDEX FROM 1 BY 1 + UNTIL WS-INDEX > WS-SORT-MAX + DISPLAY "Element " WS-INDEX ": " WS-SORT-ROW(WS-INDEX) + END-PERFORM. + + STOP RUN. + \ No newline at end of file diff --git a/lab-5/scanner.flex b/lab-5/scanner.flex index 69284c9..ca9acac 100644 --- a/lab-5/scanner.flex +++ b/lab-5/scanner.flex @@ -1,47 +1,64 @@ %{ #include "parser.h" %} - -%option nounput -%option noinput -%option noyywrap -%option yylineno - -DIGIT [0-9] -LETTER [a-zA-Z_] - +NAME [a-zA-Z]([a-zA-Z0-9_-]*[a-zA-Z0-9])? +DIGIT [0-9]+ %% -[ \n\r\t]* /* skip whitespace */; -"print" return TOKEN_KEYWORD_PRINT; -"if" return TOKEN_KEYWORD_IF; -"then" return TOKEN_KEYWORD_THEN; -"endif" return TOKEN_KEYWORD_ENDIF; -{DIGIT}+ return TOKEN_INT; -{LETTER}+ return TOKEN_ID; -"," return TOKEN_COMMA; -"]" return TOKEN_RBRACKET; -"[" return TOKEN_LBRACKET; -"==" return TOKEN_EQUAL_EQUAL; -"!=" return TOKEN_NOT_EQUAL; -"<=" return TOKEN_LESS_THAN_OR_EQUAL; -">=" return TOKEN_GREATER_THAN_OR_EQUAL; -"<" return TOKEN_LESS_THAN; -">" return TOKEN_GREATER_THAN; -\= return TOKEN_ASSIGNMENT; -\* return TOKEN_MUL; -\+ return TOKEN_PLUS; -\- return TOKEN_MINUS; -\/ return TOKEN_DIV; -\( return TOKEN_LPAREN; -\) return TOKEN_RPAREN; -\; return TOKEN_SEMI; -. { printf("scan error: bad token: %c\n", yytext[0]); } -%% +(" "|\t|\n) /* skip whitespace */ +\*>\ ?.* +IDENTIFICATION { return TOKEN_KEYWORD_IDENTIFICATION; } +DIVISION { return TOKEN_KEYWORD_DIVISION; } +PROGRAM-ID { return TOKEN_PROGRAM_ID; } +PROCEDURE { return TOKEN_PROCEDURE; } +DATA { return TOKEN_KEYWORD_DATA; } +SECTION { return TOKEN_KEYWORD_SECTION; } +WORKING-STORAGE { return TOKEN_WORKING_STORAGE; } +DISPLAY { return TOKEN_DISPLAY; } +STOP { return TOKEN_STOP; } +RUN { return TOKEN_RUN; } +MOVE { return TOKEN_MOVE; } +TO { return TOKEN_KEYWORD_TO; } +VARYING { return TOKEN_VARYING; } +FROM { return TOKEN_KEYWORD_FROM; } +BY { return TOKEN_KEYWORD_BY; } +UNTIL { return TOKEN_UNTIL; } +PERFORM { return TOKEN_PERFORM; } +END-PERFORM { return TOKEN_END_PERFORM; } +IF { return TOKEN_IF; } +END-IF { return TOKEN_END_IF; } +SPACE { return TOKEN_SPACE; } +PIC { return TOKEN_PICTURE; } +OCCURS { return TOKEN_KEYWORD_OCCURS; } +VALUE { return TOKEN_KEYWORD_VALUE; } +COMPUTE { return TOKEN_KEYWORD_COMPUTE; } +FUNCTION { return TOKEN_KEYWORD_FUNCTION; } +X { return TOKEN_ALPHANUMERIC; } +S9 { return TOKEN_SIGNED_NUMERIC; } +9 { return TOKEN_NUMERIC; } +V9 { return TOKEN_IMPLIED_DECIMAL; } +COMP { return TOKEN_COMPUTATION_LEVEL_0; } +COMP-1 { return TOKEN_COMPUTATION_LEVEL_1; } +COMP-2 { return TOKEN_COMPUTATION_LEVEL_2; } +COMP-3 { return TOKEN_COMPUTATION_LEVEL_3; } -/* -flex calls yywrap() whenever it reaches the end of the current file. -If yywrap returns false to indicate the end of the program. -It could alternatively open up another file and return true, -so that flex would keep going. -*/ +{DIGIT} { return TOKEN_INTEGER; } +{NAME} { return TOKEN_IDENT; } +\+ { return TOKEN_ADD; } +\- { return TOKEN_SUB; } +\*\* { return TOKEN_EXPONENTIAL; } +\* { return TOKEN_MULTIPLY; } +\/ { return TOKEN_DIVIDE; } +\> { return TOKEN_GREATER_THAN; } +\< { return TOKEN_LESS_THAN; } +\= { return TOKEN_EQUAL;} + +"\""[^"]*"\"" { return TOKEN_STRING; } +"\'"[^']*"\'" { return TOKEN_STRING; } +"(" { return TOKEN_LEFT_PARENTHESIS; } +")" { return TOKEN_RIGHT_PARENTHESIS; } + +\. { return TOKEN_DOT; } + +%% +int yywrap() { return 1; }