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; }