Merge branch 'main' of gitlab.cs.wallawalla.edu:lustje/language-interpreter-lab into josh_11_7

This commit is contained in:
Josh 2024-11-11 11:09:20 -08:00
commit 4a92867792
27 changed files with 404 additions and 424 deletions

View File

@ -16,7 +16,7 @@ UTEST_MAIN();
UTEST(parser, math) { UTEST(parser, math) {
// Must include the null character to terminate input // 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)); YY_BUFFER_STATE buffer = yy_scan_buffer(string, sizeof(string));
yylineno = 1; yylineno = 1;
@ -28,20 +28,6 @@ UTEST(parser, math) {
ASSERT_EQ(result, 0); 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) { UTEST(parser, hello) {
// Read sample file as input // Read sample file as input
yyin = fopen("samples/hello-world.cbl", "r"); yyin = fopen("samples/hello-world.cbl", "r");
@ -71,7 +57,7 @@ UTEST(parser, print) {
UTEST(parser, branching) { UTEST(parser, branching) {
// Must include the null character to terminate input // 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)); YY_BUFFER_STATE buffer = yy_scan_buffer(string, sizeof(string));
yylineno = 1; yylineno = 1;
@ -84,7 +70,20 @@ UTEST(parser, branching) {
} }
UTEST(parser, looping) { 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)); YY_BUFFER_STATE buffer = yy_scan_buffer(string, sizeof(string));
yylineno = 1; yylineno = 1;
@ -121,17 +120,3 @@ UTEST(parser, quadratic) {
// Assert the result to test correctness // Assert the result to test correctness
ASSERT_EQ(result, 0); 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);
}

View File

@ -51,7 +51,6 @@ int yylex();
%token TOKEN_LEFT_PARENTHESIS %token TOKEN_LEFT_PARENTHESIS
%token TOKEN_RIGHT_PARENTHESIS %token TOKEN_RIGHT_PARENTHESIS
%token TOKEN_DOT %token TOKEN_DOT
%token TOKEN_COMMENT
%token TOKEN_ADD %token TOKEN_ADD
%token TOKEN_SUB %token TOKEN_SUB
%token TOKEN_MULTIPLY %token TOKEN_MULTIPLY
@ -65,7 +64,9 @@ int yylex();
%% %%
file : statements file : statements
statements : statements statement statements : statement_list
;
statement_list : statement_list statement
| statement | statement
; ;
statement : section statement : section
@ -85,22 +86,18 @@ type : TOKEN_KEYWORD_IDENTIFICATION
| TOKEN_STOP | TOKEN_STOP
| TOKEN_KEYWORD_DATA | TOKEN_KEYWORD_DATA
; ;
simple_stmt : cbl_function simple_stmt : cbl_func_stmt
| cbl_function param
| cbl_function assignment_stmt
| cbl_function param assignment_stmt
| cbl_function TOKEN_IDENT assignment_stmt
| if_branch | if_branch
| perform_stmt
; ;
expression : op_parms cbl_func_stmt : cbl_function
| bool | cbl_function op_parms
; | cbl_function assignment_stmt
bool : op_parms TOKEN_EQUAL op_parms | cbl_function op_parms assignment_stmt
; ;
assignment_stmt : TOKEN_EQUAL ext_function assignment_stmt : TOKEN_EQUAL ext_function
| TOKEN_EQUAL function | TOKEN_EQUAL function
| TOKEN_KEYWORD_TO TOKEN_IDENT | TOKEN_KEYWORD_TO op_parms
| TOKEN_KEYWORD_TO TOKEN_IDENT categry_contain
; ;
op_parms : op_parms TOKEN_ADD op_parms op_parms : op_parms TOKEN_ADD op_parms
| op_parms TOKEN_SUB 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_EXPONENTIAL op_parms
| op_parms TOKEN_LESS_THAN op_parms | op_parms TOKEN_LESS_THAN op_parms
| op_parms TOKEN_GREATER_THAN op_parms | op_parms TOKEN_GREATER_THAN op_parms
| op_parms TOKEN_EQUAL op_parms
| TOKEN_SUB op_parms | TOKEN_SUB op_parms
| TOKEN_LEFT_PARENTHESIS op_parms TOKEN_RIGHT_PARENTHESIS | TOKEN_LEFT_PARENTHESIS op_parms TOKEN_RIGHT_PARENTHESIS
| TOKEN_IDENT | expr
| TOKEN_INTEGER | op_parms op_parms
; ;
param : TOKEN_IDENT expr : TOKEN_IDENT
| TOKEN_INTEGER
| TOKEN_STRING | TOKEN_STRING
| param param | TOKEN_SPACE
; ;
function : op_parms function : op_parms
; ;
@ -127,11 +126,14 @@ cbl_function : TOKEN_DISPLAY
| TOKEN_KEYWORD_COMPUTE | TOKEN_KEYWORD_COMPUTE
| TOKEN_PERFORM | TOKEN_PERFORM
; ;
if_branch : TOKEN_IF expression if_branch : TOKEN_IF op_parms
| TOKEN_ELSE_IF expression | TOKEN_ELSE_IF op_parms
| TOKEN_ELSE statement | TOKEN_ELSE statement
| TOKEN_END_IF | 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 data_space : TOKEN_WORKING_STORAGE
| TOKEN_KEYWORD_SECTION | TOKEN_KEYWORD_SECTION
| TOKEN_DOT | TOKEN_DOT
@ -142,9 +144,10 @@ data_category : TOKEN_ALPHANUMERIC
| TOKEN_IMPLIED_DECIMAL | TOKEN_IMPLIED_DECIMAL
; ;
categry_contain : TOKEN_LEFT_PARENTHESIS TOKEN_INTEGER TOKEN_RIGHT_PARENTHESIS categry_contain : TOKEN_LEFT_PARENTHESIS TOKEN_INTEGER TOKEN_RIGHT_PARENTHESIS
| TOKEN_LEFT_PARENTHESIS TOKEN_IDENT TOKEN_RIGHT_PARENTHESIS
; ;
complete_category: complete_category complete_category complete_category: data_category categry_contain
| data_category categry_contain | data_category categry_contain complete_category
; ;
data_clause : TOKEN_COMPUTATION_LEVEL_0 data_clause : TOKEN_COMPUTATION_LEVEL_0
| TOKEN_COMPUTATION_LEVEL_1 | TOKEN_COMPUTATION_LEVEL_1
@ -158,15 +161,18 @@ full_data_clause: data_clause data_clause
; ;
simple_decl : TOKEN_INTEGER TOKEN_IDENT TOKEN_DOT simple_decl : TOKEN_INTEGER TOKEN_IDENT TOKEN_DOT
; ;
full_decl : TOKEN_INTEGER TOKEN_IDENT TOKEN_PICTURE complete_category TOKEN_DOT complex_decl : TOKEN_INTEGER TOKEN_IDENT TOKEN_PICTURE category_spec 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 category_spec : complete_category
| complete_category data_clauses
;
data_clauses : full_data_clause
| full_data_clause TOKEN_INTEGER
; ;
data_declaration: simple_decl data_declaration: simple_decl
| full_decl | complex_decl
; ;
%% %%
void yyerror(const char* msg) { 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);

View File

@ -6,7 +6,7 @@ DIGIT [0-9]+
%% %%
(" "|\t|\n) /* skip whitespace */ (" "|\t|\n) /* skip whitespace */
\*>\ ?.* { return TOKEN_COMMENT; } \*>\ ?.*
IDENTIFICATION { return TOKEN_KEYWORD_IDENTIFICATION; } IDENTIFICATION { return TOKEN_KEYWORD_IDENTIFICATION; }
DIVISION { return TOKEN_KEYWORD_DIVISION; } DIVISION { return TOKEN_KEYWORD_DIVISION; }
PROGRAM-ID { return TOKEN_PROGRAM_ID; } PROGRAM-ID { return TOKEN_PROGRAM_ID; }

View File

@ -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 <https://www.gnu.org/licenses/>. */
/* 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 */

View File

@ -20,7 +20,7 @@ scanner.c: scanner.flex parser.h
flex -oscanner.c scanner.flex flex -oscanner.c scanner.flex
parser.c parser.h: parser.bison 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. # clean causes all intermediate files to be deleted.

View File

@ -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 <stmt> program statement_list statement print_statement assignment_statement if_statement block
%type <expr> expr term factor name sum array_subscript star_expr
%type <decl> declaration
%{ %{
#define YYDEBUG 1 #define YYDEBUG 1
#include <stdio.h>
#include <math.h> #include <math.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "expr.h" #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. Clunky: Manually declare the interface to the scanner generated by flex.
*/ */
extern int yylineno;
extern char *yytext; extern char *yytext;
extern int yylex(); 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, Clunky: Keep the final result of the parse in a global variable,
so that it can be retrieved by main(). so that it can be retrieved by main().
*/ */
struct stmt * parser_result = 0; struct expr * parser_result = 0;
%} %}
%debug
%define parse.error detailed
%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
%% %%
file : statements
/* Here is the grammar: program is the start symbol. */ statements : statement_list
;
program : statement_list statement_list : statement_list statement
{ parser_result = $1; return 0; } | statement
;
statement : section
| sect_data
| simple_stmt
| data_space
| data_declaration
; ;
statement_list : statement section : type TOKEN_KEYWORD_DIVISION TOKEN_DOT
{ $$ = $1; } | type TOKEN_RUN TOKEN_DOT
| statement statement_list
{ $$ = $1; $1->next = $2; }
; ;
sect_data : TOKEN_PROGRAM_ID TOKEN_DOT TOKEN_IDENT TOKEN_DOT
block : statement
{ $$ = $1; }
| statement block
{ $$ = $1; $1->next = $2; }
; ;
type : TOKEN_KEYWORD_IDENTIFICATION
statement : assignment_statement TOKEN_SEMI | TOKEN_PROCEDURE
{ $$ = $1; } | TOKEN_STOP
| print_statement TOKEN_SEMI | TOKEN_KEYWORD_DATA
{ $$ = $1; }
| if_statement
{ $$ = $1; }
; ;
simple_stmt : cbl_func_stmt
assignment_statement : declaration | if_branch
{ $$ = stmt_create(STMT_DECL,$1,0,0,0,0,0,0); } | perform_stmt
; ;
cbl_func_stmt : cbl_function
print_statement : TOKEN_KEYWORD_PRINT expr | cbl_function op_parms
{ $$ = stmt_create(STMT_PRINT,0,0,$2,0,0,0,0); } | cbl_function assignment_stmt
| cbl_function op_parms assignment_stmt
; ;
assignment_stmt : TOKEN_EQUAL ext_function
if_statement : TOKEN_KEYWORD_IF expr TOKEN_KEYWORD_THEN block TOKEN_KEYWORD_ENDIF | TOKEN_EQUAL function
{ $$ = stmt_create(STMT_IF,0,0,$2,0,$4,0,0); } | TOKEN_KEYWORD_TO op_parms
; ;
op_parms : op_parms TOKEN_ADD op_parms
declaration : name TOKEN_ASSIGNMENT expr | op_parms TOKEN_SUB op_parms
{ $$ = decl_create($1,0,$3,0,0); } | op_parms TOKEN_MULTIPLY op_parms
| array_subscript TOKEN_ASSIGNMENT expr | op_parms TOKEN_DIVIDE op_parms
{ $$ = decl_create($1,0,$3,0,0); } | 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
name : TOKEN_ID | TOKEN_INTEGER
{ $$ = expr_create_name(yytext); } | TOKEN_STRING
| TOKEN_SPACE
; ;
function : op_parms
array_subscript : name TOKEN_LBRACKET expr TOKEN_RBRACKET
{ $$ = expr_create(EXPR_SUBSCRIPT,$1,$3); }
; ;
ext_function : TOKEN_KEYWORD_FUNCTION TOKEN_IDENT TOKEN_LEFT_PARENTHESIS TOKEN_IDENT TOKEN_RIGHT_PARENTHESIS
star_expr : expr
{ $$ = expr_create(EXPR_ARRAY,$1,0); }
| expr TOKEN_COMMA star_expr
{ $$ = expr_create(EXPR_ARRAY,$1,$3); }
; ;
cbl_function : TOKEN_DISPLAY
expr : sum TOKEN_LESS_THAN sum | TOKEN_MOVE
{ $$ = expr_create(EXPR_LESS_THAN,$1,$3); } | TOKEN_KEYWORD_COMPUTE
| sum TOKEN_LESS_THAN_OR_EQUAL sum | TOKEN_PERFORM
{ $$ = 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; }
; ;
if_branch : TOKEN_IF op_parms
sum : sum TOKEN_PLUS term | TOKEN_ELSE_IF op_parms
{ $$ = expr_create(EXPR_ADD,$1,$3); } | TOKEN_ELSE statement
| sum TOKEN_MINUS term | TOKEN_END_IF
{ $$ = expr_create(EXPR_SUBTRACT,$1,$3); }
| term
{ $$ = $1; }
; ;
perform_stmt : TOKEN_PERFORM TOKEN_VARYING TOKEN_IDENT TOKEN_KEYWORD_FROM TOKEN_INTEGER TOKEN_KEYWORD_BY TOKEN_INTEGER TOKEN_UNTIL op_parms
term : term TOKEN_MUL factor | TOKEN_END_PERFORM
{ $$ = expr_create(EXPR_MULTIPLY,$1,$3); }
| term TOKEN_DIV factor
{ $$ = expr_create(EXPR_DIVIDE,$1,$3); }
| factor
{ $$ = $1; }
; ;
data_space : TOKEN_WORKING_STORAGE
factor : TOKEN_LPAREN expr TOKEN_RPAREN | TOKEN_KEYWORD_SECTION
{ $$ = $2; } | TOKEN_DOT
| TOKEN_MINUS factor ;
{ $$ = expr_create(EXPR_SUBTRACT,expr_create_integer_literal(0),$2); } data_category : TOKEN_ALPHANUMERIC
| TOKEN_INT | TOKEN_NUMERIC
{ $$ = expr_create_integer_literal(atoi(yytext)); } | TOKEN_SIGNED_NUMERIC
| TOKEN_LBRACKET star_expr TOKEN_RBRACKET | TOKEN_IMPLIED_DECIMAL
{ $$ = $2; } ;
| array_subscript categry_contain : TOKEN_LEFT_PARENTHESIS TOKEN_INTEGER TOKEN_RIGHT_PARENTHESIS
{ $$ = $1; } | TOKEN_LEFT_PARENTHESIS TOKEN_IDENT TOKEN_RIGHT_PARENTHESIS
| name ;
{ $$ = $1; } 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) { 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);
} }

View File

@ -1 +0,0 @@
a = [ 4, 8, 12 ];

View File

@ -1,2 +0,0 @@
a = [ 3, 5 ];
print a[0];

View File

@ -1,4 +0,0 @@
a = [ 3, 5, 7, 9, 11];
print a[1];
a[1] = 6;
print a[1];

View File

@ -1 +0,0 @@
a = 5;

View File

@ -0,0 +1,5 @@
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO-WORLD.
PROCEDURE DIVISION.
DISPLAY 'Hello World!'
STOP RUN.

View File

@ -1,2 +0,0 @@
print 5;
print 6;

View File

@ -1 +0,0 @@
56

View File

@ -1,2 +0,0 @@
print 5;
print 6;

View File

@ -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.

View File

@ -1,6 +0,0 @@
if 3==3 then
print 3;
endif
if 3==4 then
print 4;
endif

View File

@ -1,5 +0,0 @@
if 0 then
print 5;
print 3;
print 1;
endif

View File

@ -1,5 +0,0 @@
if 1 then
print 5;
print 3;
print 1;
endif

View File

@ -1 +0,0 @@
print 5;

View File

@ -1,2 +0,0 @@
a = 4 + 4;
print a;

View File

@ -1,2 +0,0 @@
a=(101*20)+4;
print(a);

View File

@ -1 +0,0 @@
2024

View File

@ -1,2 +0,0 @@
a = ((101*20)+4);
print(a);

View File

@ -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.

View File

@ -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.

View File

@ -1,47 +1,64 @@
%{ %{
#include "parser.h" #include "parser.h"
%} %}
NAME [a-zA-Z]([a-zA-Z0-9_-]*[a-zA-Z0-9])?
%option nounput DIGIT [0-9]+
%option noinput
%option noyywrap
%option yylineno
DIGIT [0-9]
LETTER [a-zA-Z_]
%% %%
[ \n\r\t]* /* skip whitespace */; (" "|\t|\n) /* skip whitespace */
"print" return TOKEN_KEYWORD_PRINT; \*>\ ?.*
"if" return TOKEN_KEYWORD_IF; IDENTIFICATION { return TOKEN_KEYWORD_IDENTIFICATION; }
"then" return TOKEN_KEYWORD_THEN; DIVISION { return TOKEN_KEYWORD_DIVISION; }
"endif" return TOKEN_KEYWORD_ENDIF; PROGRAM-ID { return TOKEN_PROGRAM_ID; }
{DIGIT}+ return TOKEN_INT; PROCEDURE { return TOKEN_PROCEDURE; }
{LETTER}+ return TOKEN_ID; DATA { return TOKEN_KEYWORD_DATA; }
"," return TOKEN_COMMA; SECTION { return TOKEN_KEYWORD_SECTION; }
"]" return TOKEN_RBRACKET; WORKING-STORAGE { return TOKEN_WORKING_STORAGE; }
"[" return TOKEN_LBRACKET; DISPLAY { return TOKEN_DISPLAY; }
"==" return TOKEN_EQUAL_EQUAL; STOP { return TOKEN_STOP; }
"!=" return TOKEN_NOT_EQUAL; RUN { return TOKEN_RUN; }
"<=" return TOKEN_LESS_THAN_OR_EQUAL; MOVE { return TOKEN_MOVE; }
">=" return TOKEN_GREATER_THAN_OR_EQUAL; TO { return TOKEN_KEYWORD_TO; }
"<" return TOKEN_LESS_THAN; VARYING { return TOKEN_VARYING; }
">" return TOKEN_GREATER_THAN; FROM { return TOKEN_KEYWORD_FROM; }
\= return TOKEN_ASSIGNMENT; BY { return TOKEN_KEYWORD_BY; }
\* return TOKEN_MUL; UNTIL { return TOKEN_UNTIL; }
\+ return TOKEN_PLUS; PERFORM { return TOKEN_PERFORM; }
\- return TOKEN_MINUS; END-PERFORM { return TOKEN_END_PERFORM; }
\/ return TOKEN_DIV; IF { return TOKEN_IF; }
\( return TOKEN_LPAREN; END-IF { return TOKEN_END_IF; }
\) return TOKEN_RPAREN; SPACE { return TOKEN_SPACE; }
\; return TOKEN_SEMI; PIC { return TOKEN_PICTURE; }
. { printf("scan error: bad token: %c\n", yytext[0]); } 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; }
/* {DIGIT} { return TOKEN_INTEGER; }
flex calls yywrap() whenever it reaches the end of the current file. {NAME} { return TOKEN_IDENT; }
If yywrap returns false to indicate the end of the program. \+ { return TOKEN_ADD; }
It could alternatively open up another file and return true, \- { return TOKEN_SUB; }
so that flex would keep going. \*\* { 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; }