copy over changes from main repo

This commit is contained in:
Riley Smith 2024-11-20 12:50:14 -08:00
parent 141b10c9c9
commit 5ee9afbcc1
No known key found for this signature in database
GPG Key ID: 5D27A014FD4A29C8
16 changed files with 217 additions and 167 deletions

54
expr.c
View File

@ -169,6 +169,15 @@ void stmt_print(struct stmt *s) {
case STMT_END_EXECUTION:
printf("stop run\n");
break;
case STMT_PERFORM:
decl_print(s->decl);
printf("; while ");
expr_print(s->expr);
printf(" do ");
expr_print(s->next_expr);
printf("\n");
printf(" ");
stmt_print(s->body);
}
stmt_print(s->next);
@ -312,11 +321,33 @@ void stmt_evaluate(struct stmt *s) {
case STMT_COMPUTE:
stmt_evaluate_compute(s);
break;
case STMT_PERFORM:
// evaluate the declaration
decl_evaluate(s->decl);
// now we can loop
stmt_evaluate_perform(s);
break;
}
stmt_evaluate(s->next);
}
void stmt_evaluate_perform(struct stmt *s) {
if (!s) return;
// Initial value has already been set by decl_evaluate in stmt_evaluate
// Keep looping until the condition is met
while (!expr_evaluate(s->expr)) {
// Execute the loop body
stmt_evaluate(s->body);
// Increment the loop variable
// s->next_expr contains the increment expression (name + BY value)
decl_evaluate(decl_create(s->decl->name, NULL, s->next_expr, NULL, NULL));
}
}
void stmt_evaluate_print(struct expr *e) {
if (!e)
return;
@ -328,6 +359,9 @@ void stmt_evaluate_print(struct expr *e) {
printf("%f", expr_evaluate(e));
} else if (e->kind == EXPR_INTEGER_LITERAL || e->kind == EXPR_SUBSCRIPT) {
printf("%.0f", expr_evaluate(e));
if (e->kind == EXPR_SUBSCRIPT) {
return;
}
} else if (e->kind == EXPR_NAME) {
struct expr *value = scope_lookup(e->name);
stmt_evaluate_print(value);
@ -356,7 +390,7 @@ void decl_evaluate(struct decl *d) {
return;
}
if (d->name->kind == EXPR_NAME && d->value->kind == EXPR_ARRAY) {
struct expr *e = expr_sub_evaluate(d->value);
struct expr *e = expr_sub_evaluate(d->value, d->type);
scope_bind(d->name->name, e);
} else if (d->name->kind == EXPR_NAME) {
if (d->value->kind != EXPR_STRING_LITERAL) {
@ -387,7 +421,7 @@ void decl_subscript_evaluate(struct expr *e, float value) {
exit(1);
}
if (e->left->kind != EXPR_NAME) {
if (e->left == NULL || e->left->kind != EXPR_NAME) {
printf("runtime error: subscript has no name\n");
exit(1);
}
@ -395,6 +429,10 @@ void decl_subscript_evaluate(struct expr *e, float value) {
// Get array expresion
struct expr *a = scope_lookup(e->left->name);
float index = expr_evaluate(e->right);
if (!a) {
printf("runtime error: array not found\n");
exit(1);
}
// Find the right offset
while (index > 0) {
@ -437,14 +475,20 @@ const char *expr_string_evaluate(struct expr *e) {
return "";
}
struct expr *expr_sub_evaluate(struct expr *e) {
struct expr *expr_sub_evaluate(struct expr *e, struct type *t) {
/* Careful: Return zero on null pointer. */
if (!e)
return 0;
// TODO evaluate each item in the array and save the result
if (!e->right) {
for (int i = 0; i < t->limit; i++) {
struct expr *temp = expr_create_float_literal(0);
e->right = expr_create(EXPR_ARRAY_ITEM, temp, e->right);
}
return e;
}
return expr_sub_evaluate(e->right, t);
}
/*
@ -462,7 +506,7 @@ float expr_subscript_evaluate(struct expr *e) {
exit(1);
}
if (e->left->kind != EXPR_NAME) {
if (e->left == NULL || e->left->kind != EXPR_NAME) {
printf("runtime error: subscript has no name\n");
exit(1);
}

12
expr.h
View File

@ -37,7 +37,8 @@ typedef enum {
EXPR_NULL,
EXPR_CUSTOM_FUNCTION,
EXPR_OCCURS,
EXPR_VALUE
EXPR_VALUE,
EXPR_ARRAY_ITEM,
} expr_t;
struct expr {
@ -55,7 +56,8 @@ typedef enum {
TYPE_ALPHANUMERIC,
TYPE_IMPLIED_DECIMAL,
TYPE_NUMERIC,
TYPE_SIGNED_NUMERIC
TYPE_SIGNED_NUMERIC,
TYPE_ARRAY
} type_t;
typedef enum { LEVEL_0, LEVEL_1, LEVEL_2, LEVEL_3 } computation_level_t;
@ -86,6 +88,7 @@ typedef enum {
STMT_COMPUTE,
STMT_MOVE,
STMT_END_EXECUTION,
STMT_PERFORM
} stmt_t;
struct stmt {
@ -124,11 +127,12 @@ void ast_print(struct stmt *e);
void stmt_evaluate(struct stmt *e);
void stmt_evaluate_compute(struct stmt *e);
void decl_evaluate(struct decl *e);
void stmt_evaluate_print(struct expr *e);
void stmt_evaluate_perform(struct stmt *s);
void decl_evaluate(struct decl *e);
void decl_subscript_evaluate(struct expr *e, float value);
float expr_evaluate(struct expr *e);
struct expr *expr_sub_evaluate(struct expr *e);
struct expr *expr_sub_evaluate(struct expr *e, struct type *t);
float expr_subscript_evaluate(struct expr *e);
const char *expr_string_evaluate(struct expr *e);
float expr_evaluate_custom_function(struct expr *e);

View File

@ -135,11 +135,17 @@ UTEST_F(InterpreterTestFile, branching) {
utest_fixture->evaluated_file = "samples/outputs/branching_evaluate.txt";
}
// UTEST_F(InterpreterTestFile, looping) {
// utest_fixture->test_file = "samples/looping.cbl";
// utest_fixture->print_file = "samples/outputs/looping_print.txt";
// utest_fixture->evaluated_file = "samples/outputs/looping_evaluate.txt";
// }
UTEST_F(InterpreterTestFile, looping) {
utest_fixture->test_file = "samples/looping.cbl";
utest_fixture->print_file = "samples/outputs/looping_print.txt";
utest_fixture->evaluated_file = "samples/outputs/looping_evaluate.txt";
}
UTEST_F(InterpreterTestFile, array) {
utest_fixture->test_file = "samples/array.cbl";
utest_fixture->print_file = "samples/outputs/array_print.txt";
utest_fixture->evaluated_file = "samples/outputs/array_evaluate.txt";
}
UTEST_F(InterpreterTestFile, helloworld) {
utest_fixture->test_file = "samples/hello-world.cbl";
@ -153,8 +159,8 @@ UTEST_F(InterpreterTestFile, quadratic) {
utest_fixture->evaluated_file = "samples/outputs/quadratic_evaluate.txt";
}
// UTEST_F(InterpreterTestFile, sorting) {
// utest_fixture->test_file = "samples/sorting-snippet.cbl";
// utest_fixture->print_file = "samples/outputs/sorting_print.txt";
// utest_fixture->evaluated_file = "samples/outputs/sorting_evaluate.txt";
// }
UTEST_F(InterpreterTestFile, sorting) {
utest_fixture->test_file = "samples/sorting-snippet.cbl";
utest_fixture->print_file = "samples/outputs/sorting_print.txt";
utest_fixture->evaluated_file = "samples/outputs/sorting_evaluate.txt";
}

View File

@ -94,7 +94,7 @@ extern struct stmt *parser_result = 0;
struct type *type;
}
%type <stmt> statement_list statement section stop_run sect_data simple_stmt cbl_func_stmt if_branch else_parts else_branch perform_stmt data_space display_stmt assignment_stmt
%type <stmt> statement_list statement section stop_run sect_data simple_stmt cbl_func_stmt if_branch else_parts else_branch perform_stmt data_space display_stmt assignment_stmt perform_header
%type <expr> mathmaticalexpr booleanexpr term op_parm container_expr type_expr op_parms math_op categry_contain category_value ident ext_function
%type <decl> simple_decl complex_decl data_declaration category_spec
%type <type> data_category complete_category data_clause
@ -138,6 +138,7 @@ simple_stmt : cbl_func_stmt
| if_branch
{$$ = $1;}
| perform_stmt
{$$ = $1;}
;
cbl_func_stmt : display_stmt
{$$ = $1;}
@ -182,7 +183,7 @@ mathmaticalexpr : type_expr
| container_expr
{$$ = $1;}
| type_expr container_expr
{$$ = $1; $1->right = $2;}
{ $$ = expr_create(EXPR_SUBSCRIPT, $1, $2);}
;
container_expr : TOKEN_LEFT_PARENTHESIS mathmaticalexpr TOKEN_RIGHT_PARENTHESIS
{$$ = $2;}
@ -223,8 +224,14 @@ else_branch : TOKEN_ELSE_IF booleanexpr simple_stmt
{$$ = stmt_create(STMT_IF, NULL, NULL, expr_create(EXPR_EQUAL_EQUAL, expr_create_integer_literal(0), expr_create_integer_literal(0)), NULL, $2, NULL, NULL);}
| TOKEN_END_IF
{$$ = NULL;}
perform_stmt : TOKEN_PERFORM TOKEN_VARYING ident TOKEN_KEYWORD_FROM TOKEN_INTEGER TOKEN_KEYWORD_BY TOKEN_INTEGER TOKEN_UNTIL op_parms
| TOKEN_END_PERFORM
perform_stmt : perform_header statement_list TOKEN_END_PERFORM
{$1->body = $2; $$=$1;}
;
// for (int i = 0; i < 10 i++)
perform_header : TOKEN_PERFORM TOKEN_VARYING ident TOKEN_KEYWORD_FROM type_expr TOKEN_KEYWORD_BY type_expr TOKEN_UNTIL op_parms
{
$$ = stmt_create(STMT_PERFORM, decl_create($3, NULL, $5, NULL, NULL), NULL, $9, expr_create(EXPR_ADD, $3, $7), NULL, NULL, NULL);
}
;
data_space : TOKEN_WORKING_STORAGE TOKEN_KEYWORD_SECTION TOKEN_DOT
;
@ -264,7 +271,12 @@ category_value : TOKEN_KEYWORD_VALUE TOKEN_INTEGER
{$$ = expr_create(EXPR_NULL, NULL, NULL);}
;
category_spec : complete_category data_clause category_value
{ $1->level = $2->level; $$ = decl_create(NULL, $1, $3, NULL, NULL);}
{
if ($3->kind == EXPR_OCCURS) {
$1->limit = $3->integer_value;
$3->kind = EXPR_ARRAY;
}
$1->level = $2->level; $$ = decl_create(NULL, $1, $3, NULL, NULL);}
;
//TODO: implement levels
simple_decl : TOKEN_INTEGER ident TOKEN_DOT

View File

@ -1,117 +0,0 @@
%{
#define YYDEBUG 1
#include <stdio.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.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 stmt *
/*
Clunky: Manually declare the interface to the scanner generated by flex.
*/
extern char *yytext;
extern int yylex();
// void yyerror(struct stmt *parser_result, const char*);
void yyerror(const char*);
extern int yylineno;
struct stmt *parser_result = 0;
%}
// %parse-param {struct stmt *parser_result}
%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
{parser_result = $1; return 0;}
;
statements : statements statement
{ $$ = $1; $1->next = $2; }
| statement
{ $$ = $1; }
;
statement : simple_stmt
{$$ = stmt_create(STMT_BLOCK, NULL, NULL, NULL, NULL, $1, NULL, NULL);}
;
simple_stmt : cbl_func_stmt
{$$ = $1;}
;
cbl_func_stmt : display_stmt
{$$ = $1;}
;
display_stmt : TOKEN_DISPLAY expr
{$$ = stmt_create(STMT_PRINT, NULL, NULL, $2, NULL, NULL, NULL, NULL);}
;
expr : TOKEN_STRING
{ $$ = expr_create_string_literal(yytext);}
;
%%
void yyerror(const char* msg) {
fprintf(stderr, "Error | Line: %d\n%s\n",yylineno,msg);
}

View File

@ -71,7 +71,7 @@ UTEST(parser, branching) {
}
UTEST(parser, looping) {
char string[] = "PERFORM VARYING I FROM 1 BY 1 UNTIL I > 10\0";
char string[] = "PERFORM VARYING I FROM 1 BY 1 UNTIL I > 10 DISPLAY I END-PERFORM\0";
YY_BUFFER_STATE buffer = yy_scan_buffer(string, sizeof(string));
yylineno = 1;

18
samples/array.cbl Normal file
View File

@ -0,0 +1,18 @@
IDENTIFICATION DIVISION.
PROGRAM-ID. array.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-ARRAY.
05 WS-ARRAY-ROW PIC S9(4) OCCURS 4.
05 WS-ARRAY-INDEX PIC 9(3) VALUE 1.
PROCEDURE DIVISION.
MOVE 5 TO WS-ARRAY-ROW(1)
MOVE 10 TO WS-ARRAY-ROW(2)
MOVE 43 TO WS-ARRAY-ROW(3)
MOVE 101 TO WS-ARRAY-ROW(4)
DISPLAY "The first element is: " WS-ARRAY-ROW(1)
DISPLAY "The second element is: " WS-ARRAY-ROW(2)
DISPLAY "The third element is: " WS-ARRAY-ROW(3)
DISPLAY "The fourth element is: " WS-ARRAY-ROW(4)
STOP RUN.

View File

@ -1,7 +1,12 @@
IDENTIFICATION DIVISION.
PROGRAM-ID. LOOPING.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-I PIC 9(3) VALUE 1.
PROCEDURE DIVISION.
PERFORM VARYING I FROM 1 BY 1 UNTIL I > 10
DISPLAY I
PERFORM VARYING WS-I FROM 1 BY 1 UNTIL WS-I > 10
DISPLAY WS-I
END-PERFORM
STOP RUN.

View File

@ -0,0 +1,4 @@
The first element is: 5
The second element is: 10
The third element is: 43
The fourth element is: 101

View File

@ -0,0 +1,17 @@
section
section
section
section
WS-ARRAY = ();
WS-ARRAY-ROW = [];
WS-ARRAY-INDEX = 1;
section
move 5 to WS-ARRAY-ROW[1];
move 10 to WS-ARRAY-ROW[2];
move 43 to WS-ARRAY-ROW[3];
move 101 to WS-ARRAY-ROW[4];
print The first element is: WS-ARRAY-ROW[1];
print The second element is: WS-ARRAY-ROW[2];
print The third element is: WS-ARRAY-ROW[3];
print The fourth element is: WS-ARRAY-ROW[4];
stop run

View File

@ -0,0 +1,10 @@
1.000000
2.000000
3.000000
4.000000
5.000000
6.000000
7.000000
8.000000
9.000000
10.000000

View File

@ -0,0 +1,9 @@
section
section
section
section
WS-I = 1;
section
WS-I = 1; while (WS-I>10) do (WS-I+1)
print WS-I;
stop run

View File

@ -1,15 +1,15 @@
Original Array Contents:
---------------------
Element +0001: 30
Element +0002: 10
Element +0003: 50
Element +0004: 20
Element +0005: 40
Element 1.000000: 30
Element 2.000000: 10
Element 3.000000: 50
Element 4.000000: 20
Element 5.000000: 40
Sorted Array Contents:
--------------------
Element +0001: 10
Element +0002: 20
Element +0003: 30
Element +0004: 40
Element +0005: 50
Element 1.000000: 10
Element 2.000000: 20
Element 3.000000: 30
Element 4.000000: 40
Element 5.000000: 50

View File

@ -0,0 +1,38 @@
section
section
section
section
WS-SORT-AREA = ();
WS-SORT-TABLE = ();
WS-SORT-ROW = [];
WS-TEMP-ROW = ();
WS-ROW-MAX = 100;
WS-SORT-MAX = ();
WS-I = ();
WS-J = ();
WS-INDEX = ();
section
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;
print Original Array Contents:;
print ---------------------;
WS-INDEX = 1; while (WS-INDEX>WS-SORT-MAX) do (WS-INDEX+1)
print Element WS-INDEX: WS-SORT-ROW[WS-INDEX];
print ;
WS-I = 1; while (WS-I>(WS-SORT-MAX-1)) do (WS-I+1)
WS-J = 1; while (WS-J>(WS-SORT-MAX-WS-I)) do (WS-J+1)
if (WS-SORT-ROW[WS-J]>WS-SORT-ROW[(WS-J+1)]) then
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)];
endif
print Sorted Array Contents:;
print --------------------;
WS-INDEX = 1; while (WS-INDEX>WS-SORT-MAX) do (WS-INDEX+1)
print Element WS-INDEX: WS-SORT-ROW[WS-INDEX];
stop run

View File

@ -4,8 +4,8 @@ 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).
10 WS-SORT-ROW PIC S9(4) OCCURS 100.
05 WS-TEMP-ROW PIC S9(4).
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.
@ -14,11 +14,11 @@ WORKING-STORAGE SECTION.
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 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
@ -28,7 +28,7 @@ PROCEDURE DIVISION.
UNTIL WS-INDEX > WS-SORT-MAX
DISPLAY "Element " WS-INDEX ": " WS-SORT-ROW(WS-INDEX)
END-PERFORM
DISPLAY SPACE
DISPLAY ""
*> * Simplified bubble sort
PERFORM VARYING WS-I FROM 1 BY 1

View File

@ -31,7 +31,7 @@ UTEST(scanner, hello) {
{TOKEN_KEYWORD_DIVISION, "DIVISION"},
{TOKEN_DOT, "."},
{TOKEN_DISPLAY, "DISPLAY"},
{TOKEN_STRING, "Hello World!"},
{TOKEN_STRING, "'Hello World!'"},
{TOKEN_STOP, "STOP"},
{TOKEN_RUN, "RUN"},
{TOKEN_DOT, "."},