Merge branch 'josh_11_7' into 'main'
add bison interpreter See merge request lustje/language-interpreter-lab!10
This commit is contained in:
commit
0f4472a555
|
|
@ -8,7 +8,7 @@ extern char *yytext;
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
FILE *file;
|
FILE *file;
|
||||||
const char *filename = "samples/quadratic_snippet.cbl"; // Default filename
|
const char *filename = "samples/quadratic-snippet.cbl";
|
||||||
|
|
||||||
// Check if a filename is provided as a command-line argument
|
// Check if a filename is provided as a command-line argument
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
|
|
@ -25,6 +25,6 @@ int main(int argc, char *argv[]) {
|
||||||
token_t t = yylex();
|
token_t t = yylex();
|
||||||
if (t == TOKEN_EOF)
|
if (t == TOKEN_EOF)
|
||||||
break;
|
break;
|
||||||
printf("token: %d text: %s\n", t, yytext);
|
printf("token: %d, text: %s\n", t, yytext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ struct token_st {
|
||||||
|
|
||||||
UTEST(scanner, hello) {
|
UTEST(scanner, hello) {
|
||||||
struct token_st tokens[] = {
|
struct token_st tokens[] = {
|
||||||
{TOKEN_IDENTIFICATION, "IDENTIFICATION"},
|
{TOKEN_KEYWORD_IDENTIFICATION, "IDENTIFICATION"},
|
||||||
{TOKEN_KEYWORD_DIVISION, "DIVISION"},
|
{TOKEN_KEYWORD_DIVISION, "DIVISION"},
|
||||||
{TOKEN_DOT, "."},
|
{TOKEN_DOT, "."},
|
||||||
{TOKEN_PROGRAM_ID, "PROGRAM-ID"},
|
{TOKEN_PROGRAM_ID, "PROGRAM-ID"},
|
||||||
|
|
@ -53,10 +53,7 @@ UTEST(scanner, hello) {
|
||||||
|
|
||||||
UTEST(scanner, quadratic) {
|
UTEST(scanner, quadratic) {
|
||||||
struct token_st tokens[] = {
|
struct token_st tokens[] = {
|
||||||
{TOKEN_COMMENT, "*> Code altered from https://www.quora.com/What-is-a-COBOL-program-that-will-solve-a-quadratic-equation"},
|
{TOKEN_KEYWORD_IDENTIFICATION, "IDENTIFICATION"},
|
||||||
{TOKEN_COMMENT, "*> Program finds the roots to a simple quadratic equation"},
|
|
||||||
|
|
||||||
{TOKEN_IDENTIFICATION, "IDENTIFICATION"},
|
|
||||||
{TOKEN_KEYWORD_DIVISION, "DIVISION"},
|
{TOKEN_KEYWORD_DIVISION, "DIVISION"},
|
||||||
{TOKEN_DOT, "."},
|
{TOKEN_DOT, "."},
|
||||||
{TOKEN_PROGRAM_ID, "PROGRAM-ID"},
|
{TOKEN_PROGRAM_ID, "PROGRAM-ID"},
|
||||||
|
|
@ -180,9 +177,8 @@ UTEST(scanner, quadratic) {
|
||||||
{TOKEN_PROCEDURE, "PROCEDURE"},
|
{TOKEN_PROCEDURE, "PROCEDURE"},
|
||||||
{TOKEN_KEYWORD_DIVISION, "DIVISION"},
|
{TOKEN_KEYWORD_DIVISION, "DIVISION"},
|
||||||
{TOKEN_DOT, "."},
|
{TOKEN_DOT, "."},
|
||||||
{TOKEN_COMMENT, "*> program begins here"},
|
|
||||||
{TOKEN_DISPLAY, "DISPLAY"},
|
{TOKEN_DISPLAY, "DISPLAY"},
|
||||||
{TOKEN_STRING, "'EQUATION: (1x^2) + 5x + 6 = 0'"},
|
{TOKEN_STRING, "\"EQUATION: (1x^2) + 5x + 6 = 0\""},
|
||||||
{TOKEN_KEYWORD_COMPUTE, "COMPUTE"},
|
{TOKEN_KEYWORD_COMPUTE, "COMPUTE"},
|
||||||
{TOKEN_IDENT, "discriminant"},
|
{TOKEN_IDENT, "discriminant"},
|
||||||
{TOKEN_EQUAL, "="},
|
{TOKEN_EQUAL, "="},
|
||||||
|
|
@ -250,14 +246,14 @@ UTEST(scanner, quadratic) {
|
||||||
{TOKEN_RIGHT_PARENTHESIS, ")"},
|
{TOKEN_RIGHT_PARENTHESIS, ")"},
|
||||||
|
|
||||||
{TOKEN_DISPLAY, "DISPLAY"},
|
{TOKEN_DISPLAY, "DISPLAY"},
|
||||||
{TOKEN_STRING, "'The equation has two distinct real roots: '"},
|
{TOKEN_STRING, "\"The equation has two distinct real roots: \""},
|
||||||
|
|
||||||
{TOKEN_DISPLAY, "DISPLAY"},
|
{TOKEN_DISPLAY, "DISPLAY"},
|
||||||
{TOKEN_STRING, "'Root 1: '"},
|
{TOKEN_STRING, "\"Root 1: \""},
|
||||||
{TOKEN_IDENT, "root1"},
|
{TOKEN_IDENT, "root1"},
|
||||||
|
|
||||||
{TOKEN_DISPLAY, "DISPLAY"},
|
{TOKEN_DISPLAY, "DISPLAY"},
|
||||||
{TOKEN_STRING, "'Root 2: '"},
|
{TOKEN_STRING, "\"Root 2: \""},
|
||||||
{TOKEN_IDENT, "root2"},
|
{TOKEN_IDENT, "root2"},
|
||||||
|
|
||||||
// {TOKEN_EOF, ""},
|
// {TOKEN_EOF, ""},
|
||||||
|
|
@ -282,17 +278,18 @@ UTEST(scanner, quadratic) {
|
||||||
|
|
||||||
|
|
||||||
{TOKEN_DISPLAY, "DISPLAY"},
|
{TOKEN_DISPLAY, "DISPLAY"},
|
||||||
{TOKEN_STRING, "'The equation has one real root: '"},
|
{TOKEN_STRING, "\"The equation has one real root: \""},
|
||||||
|
|
||||||
{TOKEN_DISPLAY, "DISPLAY"},
|
{TOKEN_DISPLAY, "DISPLAY"},
|
||||||
{TOKEN_STRING, "'Root: '"},
|
{TOKEN_STRING, "\"Root: \""},
|
||||||
{TOKEN_IDENT, "root1"},
|
{TOKEN_IDENT, "root1"},
|
||||||
|
|
||||||
|
|
||||||
{TOKEN_ELSE, "ELSE"},
|
{TOKEN_ELSE, "ELSE"},
|
||||||
|
|
||||||
{TOKEN_DISPLAY, "DISPLAY"},
|
{TOKEN_DISPLAY, "DISPLAY"},
|
||||||
{TOKEN_STRING, "'The equation has no real roots.'"},
|
{TOKEN_STRING, "\"The equation has no real roots.\""},
|
||||||
|
{TOKEN_END_IF, "END-IF"},
|
||||||
|
|
||||||
// {TOKEN_EOF, ""},
|
// {TOKEN_EOF, ""},
|
||||||
|
|
||||||
|
|
@ -316,7 +313,7 @@ UTEST(scanner, quadratic) {
|
||||||
|
|
||||||
UTEST(scanner, sorting) {
|
UTEST(scanner, sorting) {
|
||||||
struct token_st tokens[] = {
|
struct token_st tokens[] = {
|
||||||
{TOKEN_IDENTIFICATION, "IDENTIFICATION"},
|
{TOKEN_KEYWORD_IDENTIFICATION, "IDENTIFICATION"},
|
||||||
{TOKEN_KEYWORD_DIVISION, "DIVISION"},
|
{TOKEN_KEYWORD_DIVISION, "DIVISION"},
|
||||||
{TOKEN_DOT, "."},
|
{TOKEN_DOT, "."},
|
||||||
{TOKEN_PROGRAM_ID, "PROGRAM-ID"},
|
{TOKEN_PROGRAM_ID, "PROGRAM-ID"},
|
||||||
|
|
@ -403,7 +400,6 @@ UTEST(scanner, sorting) {
|
||||||
{TOKEN_PROCEDURE, "PROCEDURE"},
|
{TOKEN_PROCEDURE, "PROCEDURE"},
|
||||||
{TOKEN_KEYWORD_DIVISION, "DIVISION"},
|
{TOKEN_KEYWORD_DIVISION, "DIVISION"},
|
||||||
{TOKEN_DOT, "."},
|
{TOKEN_DOT, "."},
|
||||||
{TOKEN_COMMENT, "*> Initialize test data"},
|
|
||||||
{TOKEN_MOVE, "MOVE"},
|
{TOKEN_MOVE, "MOVE"},
|
||||||
{TOKEN_STRING, "\"30\""},
|
{TOKEN_STRING, "\"30\""},
|
||||||
{TOKEN_KEYWORD_TO, "TO"},
|
{TOKEN_KEYWORD_TO, "TO"},
|
||||||
|
|
@ -443,7 +439,6 @@ UTEST(scanner, sorting) {
|
||||||
{TOKEN_INTEGER, "5"},
|
{TOKEN_INTEGER, "5"},
|
||||||
{TOKEN_KEYWORD_TO, "TO"},
|
{TOKEN_KEYWORD_TO, "TO"},
|
||||||
{TOKEN_IDENT, "WS-SORT-MAX"},
|
{TOKEN_IDENT, "WS-SORT-MAX"},
|
||||||
{TOKEN_COMMENT, "*> * Display original array"},
|
|
||||||
{TOKEN_DISPLAY, "DISPLAY"},
|
{TOKEN_DISPLAY, "DISPLAY"},
|
||||||
{TOKEN_STRING, "\"Original Array Contents:\""},
|
{TOKEN_STRING, "\"Original Array Contents:\""},
|
||||||
{TOKEN_DISPLAY, "DISPLAY"},
|
{TOKEN_DISPLAY, "DISPLAY"},
|
||||||
|
|
@ -470,7 +465,6 @@ UTEST(scanner, sorting) {
|
||||||
{TOKEN_END_PERFORM, "END-PERFORM"},
|
{TOKEN_END_PERFORM, "END-PERFORM"},
|
||||||
{TOKEN_DISPLAY, "DISPLAY"},
|
{TOKEN_DISPLAY, "DISPLAY"},
|
||||||
{TOKEN_SPACE, "SPACE"},
|
{TOKEN_SPACE, "SPACE"},
|
||||||
{TOKEN_COMMENT, "*> * Simplified bubble sort"},
|
|
||||||
{TOKEN_PERFORM, "PERFORM"},
|
{TOKEN_PERFORM, "PERFORM"},
|
||||||
{TOKEN_VARYING, "VARYING"},
|
{TOKEN_VARYING, "VARYING"},
|
||||||
{TOKEN_IDENT, "WS-I"},
|
{TOKEN_IDENT, "WS-I"},
|
||||||
|
|
@ -540,7 +534,6 @@ UTEST(scanner, sorting) {
|
||||||
{TOKEN_END_IF, "END-IF"},
|
{TOKEN_END_IF, "END-IF"},
|
||||||
{TOKEN_END_PERFORM, "END-PERFORM"},
|
{TOKEN_END_PERFORM, "END-PERFORM"},
|
||||||
{TOKEN_END_PERFORM, "END-PERFORM"},
|
{TOKEN_END_PERFORM, "END-PERFORM"},
|
||||||
{TOKEN_COMMENT, "*> * Display sorted array"},
|
|
||||||
{TOKEN_DISPLAY, "DISPLAY"},
|
{TOKEN_DISPLAY, "DISPLAY"},
|
||||||
{TOKEN_STRING, "\"Sorted Array Contents:\""},
|
{TOKEN_STRING, "\"Sorted Array Contents:\""},
|
||||||
{TOKEN_DISPLAY, "DISPLAY"},
|
{TOKEN_DISPLAY, "DISPLAY"},
|
||||||
|
|
|
||||||
|
|
@ -14,22 +14,21 @@
|
||||||
77 square-root-discriminant PIC S9(5)V9(5) COMP-3.
|
77 square-root-discriminant PIC S9(5)V9(5) COMP-3.
|
||||||
|
|
||||||
PROCEDURE DIVISION. *> program begins here
|
PROCEDURE DIVISION. *> program begins here
|
||||||
DISPLAY 'EQUATION: (1x^2) + 5x + 6 = 0'
|
DISPLAY "EQUATION: (1x^2) + 5x + 6 = 0"
|
||||||
COMPUTE discriminant = (b ** 2) - (4 * a * c)
|
COMPUTE discriminant = (b ** 2) - (4 * a * c)
|
||||||
|
|
||||||
IF discriminant > 0
|
IF discriminant > 0
|
||||||
COMPUTE square-root-discriminant = FUNCTION SQRT(discriminant)
|
COMPUTE square-root-discriminant = FUNCTION SQRT(discriminant)
|
||||||
COMPUTE root1 = (-b + square-root-discriminant) / (2 * a)
|
COMPUTE root1 = (-b + square-root-discriminant) / (2 * a)
|
||||||
COMPUTE root2 = (-b - square-root-discriminant) / (2 * a)
|
COMPUTE root2 = (-b - square-root-discriminant) / (2 * a)
|
||||||
DISPLAY 'The equation has two distinct real roots: '
|
DISPLAY "The equation has two distinct real roots: "
|
||||||
DISPLAY 'Root 1: ' root1
|
DISPLAY "Root 1: " root1
|
||||||
DISPLAY 'Root 2: ' root2
|
DISPLAY "Root 2: " root2
|
||||||
|
|
||||||
ELSE IF discriminant = 0
|
ELSE IF discriminant = 0
|
||||||
COMPUTE root1 = -b / (2 * a)
|
COMPUTE root1 = -b / (2 * a)
|
||||||
DISPLAY 'The equation has one real root: '
|
DISPLAY "The equation has one real root: "
|
||||||
DISPLAY 'Root: ' root1
|
DISPLAY "Root: " root1
|
||||||
ELSE
|
ELSE
|
||||||
DISPLAY 'The equation has no real roots.'
|
DISPLAY "The equation has no real roots."
|
||||||
|
END-IF
|
||||||
STOP RUN.
|
STOP RUN.
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -1,13 +1,17 @@
|
||||||
%{
|
%{
|
||||||
#include "token.h"
|
#include "token.h"
|
||||||
%}
|
%}
|
||||||
|
%option warn
|
||||||
|
%option nodefault
|
||||||
|
%option yylineno
|
||||||
|
|
||||||
NAME [a-zA-Z]([a-zA-Z0-9_-]*[a-zA-Z0-9])?
|
NAME [a-zA-Z]([a-zA-Z0-9_-]*[a-zA-Z0-9])?
|
||||||
DIGIT [0-9]+
|
DIGIT [0-9]+
|
||||||
%%
|
%%
|
||||||
|
|
||||||
(" "|\t|\n) /* skip whitespace */
|
(" "|\t|\n) /* skip whitespace */
|
||||||
\*>\ ?.* { return TOKEN_COMMENT; }
|
\*>\ ?.*
|
||||||
IDENTIFICATION { return TOKEN_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; }
|
||||||
PROCEDURE { return TOKEN_PROCEDURE; }
|
PROCEDURE { return TOKEN_PROCEDURE; }
|
||||||
|
|
@ -26,8 +30,8 @@ UNTIL { return TOKEN_UNTIL; }
|
||||||
PERFORM { return TOKEN_PERFORM; }
|
PERFORM { return TOKEN_PERFORM; }
|
||||||
END-PERFORM { return TOKEN_END_PERFORM; }
|
END-PERFORM { return TOKEN_END_PERFORM; }
|
||||||
IF { return TOKEN_IF; }
|
IF { return TOKEN_IF; }
|
||||||
END-IF { return TOKEN_END_IF; }
|
|
||||||
ELSE { return TOKEN_ELSE; }
|
ELSE { return TOKEN_ELSE; }
|
||||||
|
END-IF { return TOKEN_END_IF; }
|
||||||
SPACE { return TOKEN_SPACE; }
|
SPACE { return TOKEN_SPACE; }
|
||||||
PIC { return TOKEN_PICTURE; }
|
PIC { return TOKEN_PICTURE; }
|
||||||
OCCURS { return TOKEN_KEYWORD_OCCURS; }
|
OCCURS { return TOKEN_KEYWORD_OCCURS; }
|
||||||
|
|
@ -44,8 +48,6 @@ COMP-2 { return TOKEN_COMPUTATION_LEVEL_2; }
|
||||||
COMP-3 { return TOKEN_COMPUTATION_LEVEL_3; }
|
COMP-3 { return TOKEN_COMPUTATION_LEVEL_3; }
|
||||||
|
|
||||||
|
|
||||||
{DIGIT} { return TOKEN_INTEGER; }
|
|
||||||
{NAME} { return TOKEN_IDENT; }
|
|
||||||
\+ { return TOKEN_ADD; }
|
\+ { return TOKEN_ADD; }
|
||||||
\- { return TOKEN_SUB; }
|
\- { return TOKEN_SUB; }
|
||||||
\*\* { return TOKEN_EXPONENTIAL; }
|
\*\* { return TOKEN_EXPONENTIAL; }
|
||||||
|
|
@ -55,13 +57,13 @@ COMP-3 { return TOKEN_COMPUTATION_LEVEL_3; }
|
||||||
\< { return TOKEN_LESS_THAN; }
|
\< { return TOKEN_LESS_THAN; }
|
||||||
\= { return TOKEN_EQUAL;}
|
\= { return TOKEN_EQUAL;}
|
||||||
|
|
||||||
|
|
||||||
"\""[^"]*"\"" { return TOKEN_STRING; }
|
"\""[^"]*"\"" { return TOKEN_STRING; }
|
||||||
"\'"[^']*"\'" { return TOKEN_STRING; }
|
"\'"[^']*"\'" { return TOKEN_STRING; }
|
||||||
"(" { return TOKEN_LEFT_PARENTHESIS; }
|
"(" { return TOKEN_LEFT_PARENTHESIS; }
|
||||||
")" { return TOKEN_RIGHT_PARENTHESIS; }
|
")" { return TOKEN_RIGHT_PARENTHESIS; }
|
||||||
|
{NAME} { return TOKEN_IDENT; }
|
||||||
|
{DIGIT} { return TOKEN_INTEGER; }
|
||||||
|
|
||||||
\. { return TOKEN_DOT; }
|
\. { return TOKEN_DOT; }
|
||||||
|
|
||||||
%%
|
%%
|
||||||
int yywrap() { return 1; }
|
int yywrap() { return 1; }
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
typedef enum {
|
typedef enum {
|
||||||
TOKEN_EOF = 0,
|
TOKEN_EOF = 0,
|
||||||
TOKEN_IDENTIFICATION,
|
TOKEN_KEYWORD_IDENTIFICATION,
|
||||||
TOKEN_KEYWORD_DIVISION,
|
TOKEN_KEYWORD_DIVISION,
|
||||||
TOKEN_KEYWORD_DATA,
|
TOKEN_KEYWORD_DATA,
|
||||||
TOKEN_KEYWORD_SECTION,
|
TOKEN_KEYWORD_SECTION,
|
||||||
|
|
@ -21,6 +21,7 @@ typedef enum {
|
||||||
TOKEN_IF,
|
TOKEN_IF,
|
||||||
TOKEN_ELSE,
|
TOKEN_ELSE,
|
||||||
TOKEN_END_IF,
|
TOKEN_END_IF,
|
||||||
|
TOKEN_ELSE_IF,
|
||||||
TOKEN_SPACE,
|
TOKEN_SPACE,
|
||||||
TOKEN_KEYWORD_OCCURS,
|
TOKEN_KEYWORD_OCCURS,
|
||||||
TOKEN_KEYWORD_VALUE,
|
TOKEN_KEYWORD_VALUE,
|
||||||
|
|
|
||||||
|
|
@ -9,57 +9,58 @@ int yylex();
|
||||||
%debug
|
%debug
|
||||||
%define parse.error detailed
|
%define parse.error detailed
|
||||||
|
|
||||||
%token TOKEN_EOF
|
%token TOKEN_ADD
|
||||||
%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_ALPHANUMERIC
|
||||||
%token TOKEN_NUMERIC
|
|
||||||
%token TOKEN_SIGNED_NUMERIC
|
|
||||||
%token TOKEN_IMPLIED_DECIMAL
|
|
||||||
%token TOKEN_COMPUTATION_LEVEL_0
|
%token TOKEN_COMPUTATION_LEVEL_0
|
||||||
%token TOKEN_COMPUTATION_LEVEL_1
|
%token TOKEN_COMPUTATION_LEVEL_1
|
||||||
%token TOKEN_COMPUTATION_LEVEL_2
|
%token TOKEN_COMPUTATION_LEVEL_2
|
||||||
%token TOKEN_COMPUTATION_LEVEL_3
|
%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
|
%token TOKEN_DISPLAY
|
||||||
|
%token TOKEN_DIVIDE
|
||||||
|
%token TOKEN_DOT
|
||||||
|
%token TOKEN_ELSE
|
||||||
|
%token TOKEN_ELSE_IF
|
||||||
|
%token TOKEN_END_IF
|
||||||
|
%token TOKEN_END_PERFORM
|
||||||
|
%token TOKEN_EQUAL
|
||||||
|
%token TOKEN_EXPONENTIAL
|
||||||
|
%token TOKEN_GREATER_THAN
|
||||||
|
%token TOKEN_IDENT
|
||||||
|
%token TOKEN_IF
|
||||||
|
%token TOKEN_IMPLIED_DECIMAL
|
||||||
|
%token TOKEN_INTEGER
|
||||||
|
%token TOKEN_KEYWORD_BY
|
||||||
|
%token TOKEN_KEYWORD_COMPUTE
|
||||||
|
%token TOKEN_KEYWORD_DATA
|
||||||
|
%token TOKEN_KEYWORD_DIVISION
|
||||||
|
%token TOKEN_KEYWORD_FROM
|
||||||
|
%token TOKEN_KEYWORD_FUNCTION
|
||||||
|
%token TOKEN_KEYWORD_IDENTIFICATION
|
||||||
|
%token TOKEN_KEYWORD_OCCURS
|
||||||
|
%token TOKEN_KEYWORD_SECTION
|
||||||
|
%token TOKEN_KEYWORD_TO
|
||||||
|
%token TOKEN_KEYWORD_VALUE
|
||||||
|
%token TOKEN_LEFT_PARENTHESIS
|
||||||
|
%token TOKEN_LESS_THAN
|
||||||
|
%token TOKEN_MOVE
|
||||||
|
%token TOKEN_MULTIPLY
|
||||||
|
%token TOKEN_NUMERIC
|
||||||
|
%token TOKEN_PERFORM
|
||||||
|
%token TOKEN_PICTURE
|
||||||
|
%token TOKEN_PROGRAM_ID
|
||||||
|
%token TOKEN_PROCEDURE
|
||||||
|
%token TOKEN_RIGHT_PARENTHESIS
|
||||||
|
%token TOKEN_RUN
|
||||||
|
%token TOKEN_SIGNED_NUMERIC
|
||||||
|
%token TOKEN_SPACE
|
||||||
|
%token TOKEN_STOP
|
||||||
|
%token TOKEN_STRING
|
||||||
|
%token TOKEN_SUB
|
||||||
|
%token TOKEN_UNTIL
|
||||||
|
%token TOKEN_VARYING
|
||||||
|
%token TOKEN_WORKING_STORAGE
|
||||||
|
%token TOKEN_EOF
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
@ -88,55 +89,65 @@ type : TOKEN_KEYWORD_IDENTIFICATION
|
||||||
;
|
;
|
||||||
simple_stmt : cbl_func_stmt
|
simple_stmt : cbl_func_stmt
|
||||||
| if_branch
|
| if_branch
|
||||||
|
| else_parts
|
||||||
| perform_stmt
|
| perform_stmt
|
||||||
;
|
;
|
||||||
cbl_func_stmt : cbl_function
|
cbl_func_stmt : cbl_function
|
||||||
| cbl_function op_parms
|
| cbl_function op_parms
|
||||||
| cbl_function assignment_stmt
|
| cbl_function assignment_stmt
|
||||||
| cbl_function op_parms assignment_stmt
|
| cbl_function op_parm assignment_stmt
|
||||||
;
|
;
|
||||||
assignment_stmt : TOKEN_EQUAL ext_function
|
assignment_stmt : TOKEN_EQUAL op_parms
|
||||||
| TOKEN_EQUAL function
|
|
||||||
| TOKEN_KEYWORD_TO op_parms
|
| TOKEN_KEYWORD_TO op_parms
|
||||||
;
|
;
|
||||||
op_parms : op_parms TOKEN_ADD op_parms
|
op_parms : op_parm
|
||||||
| op_parms TOKEN_SUB op_parms
|
| op_parms op_parm
|
||||||
| 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
|
op_parm : mathmaticalexpr
|
||||||
|
| booleanexpr
|
||||||
|
;
|
||||||
|
term : mathmaticalexpr
|
||||||
|
;
|
||||||
|
math_op : TOKEN_ADD
|
||||||
|
| TOKEN_SUB
|
||||||
|
| TOKEN_MULTIPLY
|
||||||
|
| TOKEN_DIVIDE
|
||||||
|
| TOKEN_EXPONENTIAL
|
||||||
|
;
|
||||||
|
mathmaticalexpr : type_expr
|
||||||
|
| mathmaticalexpr math_op term
|
||||||
|
| container_expr
|
||||||
|
| type_expr container_expr
|
||||||
|
;
|
||||||
|
container_expr : TOKEN_LEFT_PARENTHESIS mathmaticalexpr TOKEN_RIGHT_PARENTHESIS
|
||||||
|
;
|
||||||
|
booleanexpr : mathmaticalexpr TOKEN_LESS_THAN term
|
||||||
|
| mathmaticalexpr TOKEN_GREATER_THAN term
|
||||||
|
| mathmaticalexpr TOKEN_EQUAL term
|
||||||
|
;
|
||||||
|
type_expr : TOKEN_IDENT
|
||||||
| TOKEN_INTEGER
|
| TOKEN_INTEGER
|
||||||
| TOKEN_STRING
|
| TOKEN_STRING
|
||||||
| TOKEN_SPACE
|
| TOKEN_SPACE
|
||||||
;
|
| TOKEN_SUB TOKEN_IDENT
|
||||||
function : op_parms
|
| ext_function
|
||||||
;
|
;
|
||||||
ext_function : TOKEN_KEYWORD_FUNCTION TOKEN_IDENT TOKEN_LEFT_PARENTHESIS TOKEN_IDENT TOKEN_RIGHT_PARENTHESIS
|
ext_function : TOKEN_KEYWORD_FUNCTION TOKEN_IDENT TOKEN_LEFT_PARENTHESIS TOKEN_IDENT TOKEN_RIGHT_PARENTHESIS
|
||||||
;
|
;
|
||||||
cbl_function : TOKEN_DISPLAY
|
cbl_function : TOKEN_DISPLAY
|
||||||
| TOKEN_MOVE
|
| TOKEN_MOVE
|
||||||
| TOKEN_KEYWORD_COMPUTE
|
| TOKEN_KEYWORD_COMPUTE
|
||||||
| TOKEN_PERFORM
|
|
||||||
;
|
;
|
||||||
if_branch : TOKEN_IF op_parms
|
if_branch : TOKEN_IF booleanexpr
|
||||||
| TOKEN_ELSE_IF op_parms
|
;
|
||||||
| TOKEN_ELSE statement
|
else_parts : TOKEN_ELSE_IF booleanexpr simple_stmt
|
||||||
|
| TOKEN_ELSE simple_stmt
|
||||||
| 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
|
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
|
| TOKEN_END_PERFORM
|
||||||
;
|
;
|
||||||
data_space : TOKEN_WORKING_STORAGE
|
data_space : TOKEN_WORKING_STORAGE TOKEN_KEYWORD_SECTION TOKEN_DOT
|
||||||
| TOKEN_KEYWORD_SECTION
|
|
||||||
| TOKEN_DOT
|
|
||||||
;
|
;
|
||||||
data_category : TOKEN_ALPHANUMERIC
|
data_category : TOKEN_ALPHANUMERIC
|
||||||
| TOKEN_NUMERIC
|
| TOKEN_NUMERIC
|
||||||
|
|
|
||||||
|
|
@ -24,12 +24,10 @@
|
||||||
DISPLAY "The equation has two distinct real roots: "
|
DISPLAY "The equation has two distinct real roots: "
|
||||||
DISPLAY "Root 1: " root1
|
DISPLAY "Root 1: " root1
|
||||||
DISPLAY "Root 2: " root2
|
DISPLAY "Root 2: " root2
|
||||||
|
|
||||||
ELSE IF discriminant = 0
|
ELSE IF discriminant = 0
|
||||||
COMPUTE root1 = -b / (2 * a)
|
COMPUTE root1 = -b / (2 * a)
|
||||||
DISPLAY "The equation has one real root: "
|
DISPLAY "The equation has one real root: "
|
||||||
DISPLAY "Root: " root1
|
DISPLAY "Root: " root1
|
||||||
ELSE
|
ELSE
|
||||||
DISPLAY "The equation has no real roots."
|
DISPLAY "The equation has no real roots."
|
||||||
|
|
||||||
STOP RUN.
|
STOP RUN.
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,6 @@ PROCEDURE DIVISION.
|
||||||
MOVE WS-SORT-ROW(WS-J) TO WS-TEMP-ROW
|
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-SORT-ROW(WS-J + 1) TO WS-SORT-ROW(WS-J)
|
||||||
MOVE WS-TEMP-ROW TO WS-SORT-ROW(WS-J + 1)
|
MOVE WS-TEMP-ROW TO WS-SORT-ROW(WS-J + 1)
|
||||||
END-IF
|
|
||||||
END-PERFORM
|
END-PERFORM
|
||||||
END-PERFORM
|
END-PERFORM
|
||||||
|
|
||||||
|
|
@ -49,7 +48,7 @@ PROCEDURE DIVISION.
|
||||||
PERFORM VARYING WS-INDEX FROM 1 BY 1
|
PERFORM VARYING WS-INDEX FROM 1 BY 1
|
||||||
UNTIL WS-INDEX > WS-SORT-MAX
|
UNTIL WS-INDEX > WS-SORT-MAX
|
||||||
DISPLAY "Element " WS-INDEX ": " WS-SORT-ROW(WS-INDEX)
|
DISPLAY "Element " WS-INDEX ": " WS-SORT-ROW(WS-INDEX)
|
||||||
END-PERFORM.
|
END-PERFORM
|
||||||
|
|
||||||
STOP RUN.
|
STOP RUN.
|
||||||
|
|
||||||
|
|
@ -2,17 +2,20 @@
|
||||||
# The top level rule indicates how to link everything together into main
|
# The top level rule indicates how to link everything together into main
|
||||||
|
|
||||||
main: main.o symbol_map.o expr.o scanner.o parser.o
|
main: main.o symbol_map.o expr.o scanner.o parser.o
|
||||||
gcc main.o symbol_map.o expr.o scanner.o parser.o -o interpreter.out -lm
|
gcc -g3 main.o symbol_map.o expr.o scanner.o parser.o -o interpreter.out -lm
|
||||||
|
|
||||||
test: main_test.o symbol_map.o expr.o scanner.o parser.o
|
test: main_test.o symbol_map.o expr.o scanner.o parser.o
|
||||||
gcc main_test.o symbol_map.o expr.o scanner.o parser.o -o interpreter_test.out -lm
|
gcc main_test.o symbol_map.o expr.o scanner.o parser.o -o interpreter_test.out -lm
|
||||||
|
|
||||||
|
parser_test: parser_test.o symbol_map.o expr.o scanner.o parser.o
|
||||||
|
gcc parser_test.o symbol_map.o expr.o scanner.o parser.o -o parser_test.out -lm
|
||||||
|
|
||||||
# This pattern indicates that any .o file depends
|
# This pattern indicates that any .o file depends
|
||||||
# upon the .c file of the same name, and all of the .h files.
|
# upon the .c file of the same name, and all of the .h files.
|
||||||
# So, if a .o file is needed, it is built automatically.
|
# So, if a .o file is needed, it is built automatically.
|
||||||
|
|
||||||
%.o: %.c *.h
|
%.o: %.c *.h
|
||||||
gcc -Wall -c $< -o $@
|
gcc -g3 -Wall -c $< -o $@
|
||||||
|
|
||||||
# Only the files generated by flex and bison need explicit rules.
|
# Only the files generated by flex and bison need explicit rules.
|
||||||
|
|
||||||
|
|
@ -20,7 +23,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.
|
||||||
|
|
||||||
|
|
|
||||||
11
lab-5/expr.c
11
lab-5/expr.c
|
|
@ -85,7 +85,9 @@ struct expr *expr_create_float_literal(float value) {
|
||||||
|
|
||||||
struct expr *expr_create_string_literal(const char *value) {
|
struct expr *expr_create_string_literal(const char *value) {
|
||||||
struct expr *e = expr_create(EXPR_STRING_LITERAL, 0, 0);
|
struct expr *e = expr_create(EXPR_STRING_LITERAL, 0, 0);
|
||||||
e->string_literal = value;
|
char *dest = malloc(sizeof(*value));
|
||||||
|
strcpy(dest, value); // copy contents of source to dest
|
||||||
|
e->string_literal = dest;
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -123,6 +125,7 @@ void stmt_print(struct stmt *s) {
|
||||||
if (!s)
|
if (!s)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
||||||
switch (s->kind) {
|
switch (s->kind) {
|
||||||
case STMT_DECL:
|
case STMT_DECL:
|
||||||
decl_print(s->decl);
|
decl_print(s->decl);
|
||||||
|
|
@ -146,6 +149,10 @@ void stmt_print(struct stmt *s) {
|
||||||
case STMT_BLOCK:
|
case STMT_BLOCK:
|
||||||
stmt_print(s->body);
|
stmt_print(s->body);
|
||||||
break;
|
break;
|
||||||
|
// we haven't implemented sections yet
|
||||||
|
case STMT_SECTION:
|
||||||
|
printf("section\n");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
stmt_print(s->next);
|
stmt_print(s->next);
|
||||||
|
|
@ -271,6 +278,8 @@ void stmt_evaluate(struct stmt *s) {
|
||||||
case STMT_BLOCK:
|
case STMT_BLOCK:
|
||||||
stmt_evaluate(s->body);
|
stmt_evaluate(s->body);
|
||||||
break;
|
break;
|
||||||
|
case STMT_SECTION:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
stmt_evaluate(s->next);
|
stmt_evaluate(s->next);
|
||||||
|
|
|
||||||
12
lab-5/expr.h
12
lab-5/expr.h
|
|
@ -20,6 +20,7 @@ typedef enum {
|
||||||
EXPR_ADD,
|
EXPR_ADD,
|
||||||
EXPR_ARRAY,
|
EXPR_ARRAY,
|
||||||
EXPR_DIVIDE,
|
EXPR_DIVIDE,
|
||||||
|
EXPR_EXPONENTIAL,
|
||||||
EXPR_EQUAL_EQUAL,
|
EXPR_EQUAL_EQUAL,
|
||||||
EXPR_FLOAT_LITERAL,
|
EXPR_FLOAT_LITERAL,
|
||||||
EXPR_GREATER_THAN,
|
EXPR_GREATER_THAN,
|
||||||
|
|
@ -60,7 +61,16 @@ struct decl {
|
||||||
struct decl *next;
|
struct decl *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum { STMT_BLOCK, STMT_DECL, STMT_EXPR, STMT_IF, STMT_PRINT } stmt_t;
|
typedef enum {
|
||||||
|
STMT_BLOCK,
|
||||||
|
STMT_DECL,
|
||||||
|
STMT_EXPR,
|
||||||
|
STMT_IF,
|
||||||
|
STMT_PRINT,
|
||||||
|
STMT_SECTION,
|
||||||
|
STMT_COMPUTE,
|
||||||
|
STMT_MOVE
|
||||||
|
} stmt_t;
|
||||||
|
|
||||||
struct stmt {
|
struct stmt {
|
||||||
stmt_t kind;
|
stmt_t kind;
|
||||||
|
|
|
||||||
20
lab-5/main.c
20
lab-5/main.c
|
|
@ -4,13 +4,19 @@ Simply invoke the parser generated by bison, and then display the output.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
|
#include "token.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
/* Clunky: Declare the parse function generated from parser.bison */
|
/* Clunky: Declare the parse function generated from parser.bison */
|
||||||
|
// extern int yyparse(struct stmt *parser_result);
|
||||||
extern int yyparse();
|
extern int yyparse();
|
||||||
|
extern char *yytext;
|
||||||
|
|
||||||
|
extern int yylex();
|
||||||
|
|
||||||
/* Clunky: Declare the result of the parser from parser.bison */
|
/* Clunky: Declare the result of the parser from parser.bison */
|
||||||
extern struct stmt *parser_result;
|
|
||||||
|
struct stmt *parser_result;
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
printf("Lab 6 Example Interpreter Compiler\n");
|
printf("Lab 6 Example Interpreter Compiler\n");
|
||||||
|
|
@ -19,11 +25,13 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
if (yyparse() == 0) {
|
if (yyparse() == 0) {
|
||||||
printf("Parse successful: ");
|
printf("Parse successful: ");
|
||||||
stmt_print(parser_result);
|
if (parser_result != NULL) {
|
||||||
printf("\n");
|
stmt_print(parser_result);
|
||||||
printf("Running the program, results in: ");
|
printf("\n");
|
||||||
stmt_evaluate(parser_result);
|
printf("Running the program, results in: ");
|
||||||
printf("\n");
|
stmt_evaluate(parser_result);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
printf("Parse failed!\n");
|
printf("Parse failed!\n");
|
||||||
|
|
|
||||||
|
|
@ -19,20 +19,45 @@ extern int yylineno;
|
||||||
|
|
||||||
UTEST_MAIN();
|
UTEST_MAIN();
|
||||||
|
|
||||||
void read_file(const char *filename, char *expected_output) {
|
char* read_file_dynamic(const char* filename) {
|
||||||
// Read the expected output from a file
|
FILE* file = fopen(filename, "r");
|
||||||
FILE *expected_file = fopen(filename, "r");
|
if (file == NULL) {
|
||||||
if (expected_file == NULL) {
|
perror("fopen");
|
||||||
perror("fopen");
|
return NULL;
|
||||||
exit(EXIT_FAILURE);
|
}
|
||||||
}
|
|
||||||
size_t n =
|
// Seek to the end of the file to determine its size
|
||||||
fread(expected_output, 1, sizeof(expected_output) - 1, expected_file);
|
fseek(file, 0, SEEK_END);
|
||||||
expected_output[n] = '\0';
|
long file_size = ftell(file);
|
||||||
fclose(expected_file);
|
fseek(file, 0, SEEK_SET);
|
||||||
|
|
||||||
|
// Allocate a buffer to hold the file contents
|
||||||
|
char* buffer = (char*)malloc(file_size + 1);
|
||||||
|
if (buffer == NULL) {
|
||||||
|
perror("malloc");
|
||||||
|
fclose(file);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the entire file into the buffer
|
||||||
|
size_t read_size = fread(buffer, 1, file_size, file);
|
||||||
|
if (read_size != file_size) {
|
||||||
|
perror("fread");
|
||||||
|
free(buffer);
|
||||||
|
fclose(file);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Null-terminate the buffer
|
||||||
|
buffer[file_size] = '\0';
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void redirect_stdout(const char *filename, int evalutate) {
|
void redirect_stdout(const char *filename, int evalutate) {
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
// Redirect stdout to a temporary file
|
// Redirect stdout to a temporary file
|
||||||
FILE *temp_file = fopen(filename, "w");
|
FILE *temp_file = fopen(filename, "w");
|
||||||
if (temp_file == NULL) {
|
if (temp_file == NULL) {
|
||||||
|
|
@ -56,42 +81,18 @@ void redirect_stdout(const char *filename, int evalutate) {
|
||||||
close(stdout_fd);
|
close(stdout_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
UTEST(interpreter, print) {
|
struct InterpreterTestFile {
|
||||||
|
const char *evaluated_file;
|
||||||
|
const char *print_file;
|
||||||
|
const char *test_file;
|
||||||
|
};
|
||||||
|
|
||||||
yyin = fopen("samples/multiple_statements.c", "r");
|
UTEST_F_SETUP(InterpreterTestFile) {
|
||||||
yyrestart(yyin);
|
|
||||||
ASSERT_TRUE(yyin);
|
|
||||||
|
|
||||||
// yylineno = 1;
|
|
||||||
yylineno = 1;
|
|
||||||
int result = yyparse();
|
|
||||||
|
|
||||||
if (result == 0) {
|
|
||||||
// Catch the standard output and compare with expected test result
|
|
||||||
redirect_stdout("test_print.txt", 0);
|
|
||||||
redirect_stdout("test_evaluate.txt", 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assert the result to test correctness
|
|
||||||
ASSERT_EQ(result, 0);
|
|
||||||
|
|
||||||
char actual_print[1024];
|
|
||||||
read_file("test_print.txt", actual_print);
|
|
||||||
char expected_print[1024];
|
|
||||||
read_file("samples/multiple_statements_print.txt", expected_print);
|
|
||||||
ASSERT_STREQ(actual_print, expected_print);
|
|
||||||
|
|
||||||
char actual_evaluate[1024];
|
|
||||||
read_file("test_evaluate.txt", actual_evaluate);
|
|
||||||
char expected_evaluate[1024];
|
|
||||||
read_file("samples/multiple_statements_evaluate.txt", expected_evaluate);
|
|
||||||
ASSERT_STREQ(actual_evaluate, expected_evaluate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UTEST_F_TEARDOWN(InterpreterTestFile) {
|
||||||
|
// and also assert and expect in teardown!
|
||||||
UTEST(interpreter, program) {
|
yyin = fopen(utest_fixture->test_file, "r");
|
||||||
yyin = fopen("samples/program.c", "r");
|
|
||||||
yyrestart(yyin);
|
yyrestart(yyin);
|
||||||
ASSERT_TRUE(yyin);
|
ASSERT_TRUE(yyin);
|
||||||
|
|
||||||
|
|
@ -107,55 +108,23 @@ UTEST(interpreter, program) {
|
||||||
// Assert the result to test correctness
|
// Assert the result to test correctness
|
||||||
ASSERT_EQ(result, 0);
|
ASSERT_EQ(result, 0);
|
||||||
|
|
||||||
char actual_print[1024];
|
char *actual_print = read_file_dynamic("test_print.txt");
|
||||||
read_file("test_print.txt", actual_print);
|
char *expected_print = read_file_dynamic(utest_fixture->print_file);
|
||||||
char expected_print[1024];
|
|
||||||
read_file("samples/program_print.txt", expected_print);
|
|
||||||
ASSERT_STREQ(actual_print, expected_print);
|
ASSERT_STREQ(actual_print, expected_print);
|
||||||
|
|
||||||
char actual_evaluate[1024];
|
char *actual_evaluate = read_file_dynamic("test_evaluate.txt");
|
||||||
read_file("test_evaluate.txt", actual_evaluate);
|
char *expected_evaluate = read_file_dynamic(utest_fixture->evaluated_file);
|
||||||
char expected_evaluate[1024];
|
|
||||||
read_file("samples/program_evaluate.txt", expected_evaluate);
|
|
||||||
ASSERT_STREQ(actual_evaluate, expected_evaluate);
|
ASSERT_STREQ(actual_evaluate, expected_evaluate);
|
||||||
}
|
}
|
||||||
|
|
||||||
// UTEST(parser, missing_new_line) {
|
UTEST_F(InterpreterTestFile, print) {
|
||||||
// // Must include the null character to terminate input
|
utest_fixture->test_file = "samples/multiple_statements.c";
|
||||||
// char string[] = "1+8/4-3\0";
|
utest_fixture->print_file = "samples/multiple_statements_print.txt";
|
||||||
// YY_BUFFER_STATE buffer = yy_scan_buffer(string, sizeof(string));
|
utest_fixture->evaluated_file = "samples/multiple_statements_evaluate.txt";
|
||||||
|
}
|
||||||
|
|
||||||
// yylineno = 1;
|
UTEST_F(InterpreterTestFile, program_file) {
|
||||||
// int result = yyparse();
|
utest_fixture->test_file = "samples/program.c";
|
||||||
|
utest_fixture->print_file = "samples/program_print.txt";
|
||||||
// yy_delete_buffer(buffer);
|
utest_fixture->evaluated_file = "samples/program_evaluate.txt";
|
||||||
|
}
|
||||||
// // Assert the result to test correctness
|
|
||||||
// ASSERT_EQ(result, 1);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// UTEST(parser, hello_world) {
|
|
||||||
// // Read sample file as input
|
|
||||||
// yyin = fopen("samples/hello.py", "r");
|
|
||||||
// yyrestart(yyin);
|
|
||||||
// ASSERT_TRUE(yyin);
|
|
||||||
|
|
||||||
// yylineno = 1;
|
|
||||||
// int result = yyparse();
|
|
||||||
|
|
||||||
// // Assert the result to test correctness
|
|
||||||
// ASSERT_EQ(result, 0);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// UTEST(parser, quadratic) {
|
|
||||||
// // Read sample file as input
|
|
||||||
// yyin = fopen("samples/quadratic.py", "r");
|
|
||||||
// yyrestart(yyin);
|
|
||||||
// ASSERT_TRUE(yyin);
|
|
||||||
|
|
||||||
// yylineno = 1;
|
|
||||||
// int result = yyparse();
|
|
||||||
|
|
||||||
// // Assert the result to test correctness
|
|
||||||
// ASSERT_EQ(result, 0);
|
|
||||||
// }
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
%{
|
%{
|
||||||
#define YYDEBUG 1
|
#define YYDEBUG 1
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -12,7 +12,7 @@ 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.
|
By default, it is an integer. In this example, we are returning a pointer to an expression.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define YYSTYPE struct expr *
|
#define YYSTYPE struct stmt *
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Clunky: Manually declare the interface to the scanner generated by flex.
|
Clunky: Manually declare the interface to the scanner generated by flex.
|
||||||
|
|
@ -20,22 +20,17 @@ Clunky: Manually declare the interface to the scanner generated by flex.
|
||||||
|
|
||||||
extern char *yytext;
|
extern char *yytext;
|
||||||
extern int yylex();
|
extern int yylex();
|
||||||
extern int yylineno;
|
|
||||||
void yyerror(const char*);
|
void yyerror(const char*);
|
||||||
|
|
||||||
|
extern int yylineno;
|
||||||
|
|
||||||
/*
|
struct stmt *parser_result = 0;
|
||||||
Clunky: Keep the final result of the parse in a global variable,
|
|
||||||
so that it can be retrieved by main().
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct expr * parser_result = 0;
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%debug
|
%debug
|
||||||
%define parse.error detailed
|
%define parse.error detailed
|
||||||
|
|
||||||
|
|
||||||
%token TOKEN_EOF
|
%token TOKEN_EOF
|
||||||
%token TOKEN_KEYWORD_IDENTIFICATION
|
%token TOKEN_KEYWORD_IDENTIFICATION
|
||||||
%token TOKEN_KEYWORD_DIVISION
|
%token TOKEN_KEYWORD_DIVISION
|
||||||
|
|
@ -88,82 +83,127 @@ struct expr * parser_result = 0;
|
||||||
%token TOKEN_EXPONENTIAL
|
%token TOKEN_EXPONENTIAL
|
||||||
%token TOKEN_DISPLAY
|
%token TOKEN_DISPLAY
|
||||||
|
|
||||||
|
|
||||||
%%
|
%%
|
||||||
file : statements
|
file : statement_list stop_run
|
||||||
statements : statement_list
|
{parser_result = $1; return 0;}
|
||||||
;
|
;
|
||||||
statement_list : statement_list statement
|
statement_list : statement statement_list
|
||||||
|
{ $$ = $1; $1->next = $2;}
|
||||||
| statement
|
| statement
|
||||||
|
{ $$ = $1; }
|
||||||
;
|
;
|
||||||
statement : section
|
statement : section
|
||||||
|
{$$ = $1;}
|
||||||
| sect_data
|
| sect_data
|
||||||
|
{$$ = $1;}
|
||||||
| simple_stmt
|
| simple_stmt
|
||||||
|
{$$ = stmt_create(STMT_BLOCK, NULL, NULL, NULL, NULL, $1, NULL, NULL);}
|
||||||
| data_space
|
| data_space
|
||||||
|
{$$ = stmt_create(STMT_SECTION, NULL, NULL, NULL, NULL, NULL, NULL, NULL);}
|
||||||
| data_declaration
|
| data_declaration
|
||||||
|
{$$ = stmt_create(STMT_BLOCK, NULL, NULL, NULL, NULL, $1, NULL, NULL);}
|
||||||
;
|
;
|
||||||
|
|
||||||
section : type TOKEN_KEYWORD_DIVISION TOKEN_DOT
|
section : type TOKEN_KEYWORD_DIVISION TOKEN_DOT
|
||||||
| type TOKEN_RUN TOKEN_DOT
|
{$$ = stmt_create(STMT_SECTION, NULL, NULL, NULL, NULL, NULL, NULL, NULL);}
|
||||||
|
;
|
||||||
|
stop_run : TOKEN_STOP TOKEN_RUN TOKEN_DOT
|
||||||
|
{$$ = stmt_create(STMT_SECTION, NULL, NULL, NULL, NULL, NULL, NULL, NULL);}
|
||||||
;
|
;
|
||||||
sect_data : TOKEN_PROGRAM_ID TOKEN_DOT TOKEN_IDENT TOKEN_DOT
|
sect_data : TOKEN_PROGRAM_ID TOKEN_DOT TOKEN_IDENT TOKEN_DOT
|
||||||
|
{$$ = stmt_create(STMT_SECTION, NULL, NULL, NULL, NULL, NULL, NULL, NULL);}
|
||||||
;
|
;
|
||||||
type : TOKEN_KEYWORD_IDENTIFICATION
|
type : TOKEN_KEYWORD_IDENTIFICATION
|
||||||
| TOKEN_PROCEDURE
|
| TOKEN_PROCEDURE
|
||||||
| TOKEN_STOP
|
|
||||||
| TOKEN_KEYWORD_DATA
|
| TOKEN_KEYWORD_DATA
|
||||||
;
|
;
|
||||||
simple_stmt : cbl_func_stmt
|
simple_stmt : cbl_func_stmt
|
||||||
|
{$$ = $1;}
|
||||||
| if_branch
|
| if_branch
|
||||||
|
| else_parts
|
||||||
| perform_stmt
|
| perform_stmt
|
||||||
;
|
;
|
||||||
cbl_func_stmt : cbl_function
|
cbl_func_stmt : cbl_function
|
||||||
| cbl_function op_parms
|
| cbl_function op_parms
|
||||||
|
{$$ = stmt_create($1->kind, NULL, NULL, $2, NULL, NULL, NULL, NULL);}
|
||||||
| cbl_function assignment_stmt
|
| cbl_function assignment_stmt
|
||||||
| cbl_function op_parms assignment_stmt
|
| cbl_function op_parm assignment_stmt
|
||||||
;
|
;
|
||||||
assignment_stmt : TOKEN_EQUAL ext_function
|
assignment_stmt : TOKEN_EQUAL op_parms
|
||||||
| TOKEN_EQUAL function
|
|
||||||
| TOKEN_KEYWORD_TO op_parms
|
| TOKEN_KEYWORD_TO op_parms
|
||||||
;
|
;
|
||||||
op_parms : op_parms TOKEN_ADD op_parms
|
op_parms : op_parm
|
||||||
| op_parms TOKEN_SUB op_parms
|
{$$ = $1;}
|
||||||
| op_parms TOKEN_MULTIPLY op_parms
|
| op_parm op_parms
|
||||||
| op_parms TOKEN_DIVIDE op_parms
|
{$$ = $1; $1->next_expr = $2;}
|
||||||
| 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
|
op_parm : mathmaticalexpr
|
||||||
|
{$$ = $1;}
|
||||||
|
| booleanexpr
|
||||||
|
{$$ = $1;}
|
||||||
|
;
|
||||||
|
term : mathmaticalexpr
|
||||||
|
{$$ = $1;}
|
||||||
|
;
|
||||||
|
math_op : TOKEN_ADD
|
||||||
|
{$$ = expr_create(EXPR_ADD, NULL, NULL);}
|
||||||
|
| TOKEN_SUB
|
||||||
|
{$$ = expr_create(EXPR_SUBTRACT, NULL, NULL);}
|
||||||
|
| TOKEN_MULTIPLY
|
||||||
|
{$$ = expr_create(EXPR_MULTIPLY, NULL, NULL);}
|
||||||
|
| TOKEN_DIVIDE
|
||||||
|
{$$ = expr_create(EXPR_DIVIDE, NULL, NULL);}
|
||||||
|
| TOKEN_EXPONENTIAL
|
||||||
|
{$$ = expr_create(EXPR_EXPONENTIAL, NULL, NULL);}
|
||||||
|
;
|
||||||
|
mathmaticalexpr : type_expr
|
||||||
|
{$$ = $1;}
|
||||||
|
| mathmaticalexpr math_op term
|
||||||
|
|
||||||
|
| container_expr
|
||||||
|
{$$ = $1;}
|
||||||
|
| type_expr container_expr
|
||||||
|
{$$ = $1; $1->next_expr = $2;}
|
||||||
|
;
|
||||||
|
container_expr : TOKEN_LEFT_PARENTHESIS mathmaticalexpr TOKEN_RIGHT_PARENTHESIS
|
||||||
|
;
|
||||||
|
booleanexpr : mathmaticalexpr TOKEN_LESS_THAN term
|
||||||
|
{$$ = expr_create(EXPR_LESS_THAN, $1, $3);}
|
||||||
|
| mathmaticalexpr TOKEN_GREATER_THAN term
|
||||||
|
{$$ = expr_create(EXPR_GREATER_THAN, $1, $3);}
|
||||||
|
| mathmaticalexpr TOKEN_EQUAL term
|
||||||
|
{$$ = expr_create(EXPR_EQUAL_EQUAL, $1, $3);}
|
||||||
|
;
|
||||||
|
type_expr : TOKEN_IDENT
|
||||||
|
{$$ = expr_create_name(yytext);}
|
||||||
| TOKEN_INTEGER
|
| TOKEN_INTEGER
|
||||||
|
{$$ = expr_create_integer_literal(atoi(yytext));}
|
||||||
| TOKEN_STRING
|
| TOKEN_STRING
|
||||||
|
{$$ = expr_create_string_literal(yytext);}
|
||||||
| TOKEN_SPACE
|
| TOKEN_SPACE
|
||||||
;
|
{$$ = expr_create_integer_literal(0);}
|
||||||
function : op_parms
|
| TOKEN_SUB TOKEN_IDENT
|
||||||
|
| ext_function
|
||||||
;
|
;
|
||||||
ext_function : TOKEN_KEYWORD_FUNCTION TOKEN_IDENT TOKEN_LEFT_PARENTHESIS TOKEN_IDENT TOKEN_RIGHT_PARENTHESIS
|
ext_function : TOKEN_KEYWORD_FUNCTION TOKEN_IDENT TOKEN_LEFT_PARENTHESIS TOKEN_IDENT TOKEN_RIGHT_PARENTHESIS
|
||||||
|
|
||||||
;
|
;
|
||||||
cbl_function : TOKEN_DISPLAY
|
cbl_function : TOKEN_DISPLAY
|
||||||
|
{$$ = stmt_create(STMT_PRINT, NULL, NULL, NULL, NULL, NULL, NULL, NULL);}
|
||||||
| TOKEN_MOVE
|
| TOKEN_MOVE
|
||||||
|
{$$ = stmt_create(STMT_MOVE, NULL, NULL, NULL, NULL, NULL, NULL, NULL);}
|
||||||
| TOKEN_KEYWORD_COMPUTE
|
| TOKEN_KEYWORD_COMPUTE
|
||||||
| TOKEN_PERFORM
|
{$$ = stmt_create(STMT_COMPUTE, NULL, NULL, NULL, NULL, NULL, NULL, NULL);}
|
||||||
;
|
;
|
||||||
if_branch : TOKEN_IF op_parms
|
if_branch : TOKEN_IF booleanexpr
|
||||||
| TOKEN_ELSE_IF op_parms
|
;
|
||||||
| TOKEN_ELSE statement
|
else_parts : TOKEN_ELSE_IF booleanexpr simple_stmt
|
||||||
|
| TOKEN_ELSE simple_stmt
|
||||||
| 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
|
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
|
| TOKEN_END_PERFORM
|
||||||
;
|
;
|
||||||
data_space : TOKEN_WORKING_STORAGE
|
data_space : TOKEN_WORKING_STORAGE TOKEN_KEYWORD_SECTION TOKEN_DOT
|
||||||
| TOKEN_KEYWORD_SECTION
|
|
||||||
| TOKEN_DOT
|
|
||||||
;
|
;
|
||||||
data_category : TOKEN_ALPHANUMERIC
|
data_category : TOKEN_ALPHANUMERIC
|
||||||
| TOKEN_NUMERIC
|
| TOKEN_NUMERIC
|
||||||
|
|
@ -199,7 +239,6 @@ data_clauses : full_data_clause
|
||||||
data_declaration: simple_decl
|
data_declaration: simple_decl
|
||||||
| complex_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);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,117 @@
|
||||||
|
%{
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,123 @@
|
||||||
|
// https://github.com/sheredom/utest.h/blob/master/utest.h
|
||||||
|
#include "utest.h"
|
||||||
|
#include "expr.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
extern int yyparse();
|
||||||
|
|
||||||
|
typedef struct yy_buffer_state *YY_BUFFER_STATE;
|
||||||
|
extern int yyrestart();
|
||||||
|
extern YY_BUFFER_STATE yy_scan_buffer(char *str, int i);
|
||||||
|
extern YY_BUFFER_STATE yy_scan_string(char *str);
|
||||||
|
extern void yy_delete_buffer(YY_BUFFER_STATE buffer);
|
||||||
|
extern FILE *yyin;
|
||||||
|
extern int yylineno;
|
||||||
|
|
||||||
|
UTEST_MAIN();
|
||||||
|
|
||||||
|
UTEST(parser, math) {
|
||||||
|
// Must include the null character to terminate input
|
||||||
|
char string[] = "COMPUTE A = (b ** 2) - (4 * a * c)\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, hello) {
|
||||||
|
// Read sample file as input
|
||||||
|
yyin = fopen("samples/hello-world.cbl", "r");
|
||||||
|
yyrestart(yyin);
|
||||||
|
ASSERT_TRUE(yyin);
|
||||||
|
|
||||||
|
yylineno = 1;
|
||||||
|
int result = yyparse();
|
||||||
|
|
||||||
|
// Assert the result to test correctness
|
||||||
|
ASSERT_EQ(result, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
UTEST(parser, print) {
|
||||||
|
// Must include the null character to terminate input
|
||||||
|
char string[] = "DISPLAY 'Hello World!'\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, branching) {
|
||||||
|
// Must include the null character to terminate input
|
||||||
|
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;
|
||||||
|
int result = yyparse();
|
||||||
|
|
||||||
|
yy_delete_buffer(buffer);
|
||||||
|
|
||||||
|
// 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\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;
|
||||||
|
int result = yyparse();
|
||||||
|
|
||||||
|
yy_delete_buffer(buffer);
|
||||||
|
|
||||||
|
// Assert the result to test correctness
|
||||||
|
ASSERT_EQ(result, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
UTEST(parser, sorting) {
|
||||||
|
// Read sample file as input
|
||||||
|
yyin = fopen("samples/sorting-snippet.cbl", "r");
|
||||||
|
yyrestart(yyin);
|
||||||
|
ASSERT_TRUE(yyin);
|
||||||
|
|
||||||
|
yylineno = 1;
|
||||||
|
int result = yyparse();
|
||||||
|
|
||||||
|
// Assert the result to test correctness
|
||||||
|
ASSERT_EQ(result, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
UTEST(parser, quadratic) {
|
||||||
|
// Read sample file as input
|
||||||
|
yyin = fopen("samples/quadratic-snippet.cbl", "r");
|
||||||
|
yyrestart(yyin);
|
||||||
|
ASSERT_TRUE(yyin);
|
||||||
|
|
||||||
|
yylineno = 1;
|
||||||
|
int result = yyparse();
|
||||||
|
|
||||||
|
// Assert the result to test correctness
|
||||||
|
ASSERT_EQ(result, 0);
|
||||||
|
}
|
||||||
|
|
@ -24,12 +24,10 @@
|
||||||
DISPLAY "The equation has two distinct real roots: "
|
DISPLAY "The equation has two distinct real roots: "
|
||||||
DISPLAY "Root 1: " root1
|
DISPLAY "Root 1: " root1
|
||||||
DISPLAY "Root 2: " root2
|
DISPLAY "Root 2: " root2
|
||||||
|
|
||||||
ELSE IF discriminant = 0
|
ELSE IF discriminant = 0
|
||||||
COMPUTE root1 = -b / (2 * a)
|
COMPUTE root1 = -b / (2 * a)
|
||||||
DISPLAY "The equation has one real root: "
|
DISPLAY "The equation has one real root: "
|
||||||
DISPLAY "Root: " root1
|
DISPLAY "Root: " root1
|
||||||
ELSE
|
ELSE
|
||||||
DISPLAY "The equation has no real roots."
|
DISPLAY "The equation has no real roots."
|
||||||
|
|
||||||
STOP RUN.
|
STOP RUN.
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,6 @@ PROCEDURE DIVISION.
|
||||||
MOVE WS-SORT-ROW(WS-J) TO WS-TEMP-ROW
|
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-SORT-ROW(WS-J + 1) TO WS-SORT-ROW(WS-J)
|
||||||
MOVE WS-TEMP-ROW TO WS-SORT-ROW(WS-J + 1)
|
MOVE WS-TEMP-ROW TO WS-SORT-ROW(WS-J + 1)
|
||||||
END-IF
|
|
||||||
END-PERFORM
|
END-PERFORM
|
||||||
END-PERFORM
|
END-PERFORM
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
%{
|
%{
|
||||||
#include "parser.h"
|
#include "token.h"
|
||||||
%}
|
%}
|
||||||
|
%option warn
|
||||||
|
%option nodefault
|
||||||
|
%option yylineno
|
||||||
|
|
||||||
NAME [a-zA-Z]([a-zA-Z0-9_-]*[a-zA-Z0-9])?
|
NAME [a-zA-Z]([a-zA-Z0-9_-]*[a-zA-Z0-9])?
|
||||||
DIGIT [0-9]+
|
DIGIT [0-9]+
|
||||||
%%
|
%%
|
||||||
|
|
@ -26,6 +30,7 @@ UNTIL { return TOKEN_UNTIL; }
|
||||||
PERFORM { return TOKEN_PERFORM; }
|
PERFORM { return TOKEN_PERFORM; }
|
||||||
END-PERFORM { return TOKEN_END_PERFORM; }
|
END-PERFORM { return TOKEN_END_PERFORM; }
|
||||||
IF { return TOKEN_IF; }
|
IF { return TOKEN_IF; }
|
||||||
|
ELSE { return TOKEN_ELSE; }
|
||||||
END-IF { return TOKEN_END_IF; }
|
END-IF { return TOKEN_END_IF; }
|
||||||
SPACE { return TOKEN_SPACE; }
|
SPACE { return TOKEN_SPACE; }
|
||||||
PIC { return TOKEN_PICTURE; }
|
PIC { return TOKEN_PICTURE; }
|
||||||
|
|
@ -42,8 +47,7 @@ COMP-1 { return TOKEN_COMPUTATION_LEVEL_1; }
|
||||||
COMP-2 { return TOKEN_COMPUTATION_LEVEL_2; }
|
COMP-2 { return TOKEN_COMPUTATION_LEVEL_2; }
|
||||||
COMP-3 { return TOKEN_COMPUTATION_LEVEL_3; }
|
COMP-3 { return TOKEN_COMPUTATION_LEVEL_3; }
|
||||||
|
|
||||||
{DIGIT} { return TOKEN_INTEGER; }
|
|
||||||
{NAME} { return TOKEN_IDENT; }
|
|
||||||
\+ { return TOKEN_ADD; }
|
\+ { return TOKEN_ADD; }
|
||||||
\- { return TOKEN_SUB; }
|
\- { return TOKEN_SUB; }
|
||||||
\*\* { return TOKEN_EXPONENTIAL; }
|
\*\* { return TOKEN_EXPONENTIAL; }
|
||||||
|
|
@ -57,8 +61,9 @@ COMP-3 { return TOKEN_COMPUTATION_LEVEL_3; }
|
||||||
"\'"[^']*"\'" { return TOKEN_STRING; }
|
"\'"[^']*"\'" { return TOKEN_STRING; }
|
||||||
"(" { return TOKEN_LEFT_PARENTHESIS; }
|
"(" { return TOKEN_LEFT_PARENTHESIS; }
|
||||||
")" { return TOKEN_RIGHT_PARENTHESIS; }
|
")" { return TOKEN_RIGHT_PARENTHESIS; }
|
||||||
|
{NAME} { return TOKEN_IDENT; }
|
||||||
|
{DIGIT} { return TOKEN_INTEGER; }
|
||||||
|
|
||||||
\. { return TOKEN_DOT; }
|
\. { return TOKEN_DOT; }
|
||||||
|
|
||||||
%%
|
%%
|
||||||
int yywrap() { return 1; }
|
int yywrap() { return 1; }
|
||||||
|
|
@ -0,0 +1,126 @@
|
||||||
|
/* 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_IF = 277, /* TOKEN_ELSE_IF */
|
||||||
|
TOKEN_ELSE = 278, /* TOKEN_ELSE */
|
||||||
|
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_ADD = 300, /* TOKEN_ADD */
|
||||||
|
TOKEN_SUB = 301, /* TOKEN_SUB */
|
||||||
|
TOKEN_MULTIPLY = 302, /* TOKEN_MULTIPLY */
|
||||||
|
TOKEN_DIVIDE = 303, /* TOKEN_DIVIDE */
|
||||||
|
TOKEN_EQUAL = 304, /* TOKEN_EQUAL */
|
||||||
|
TOKEN_GREATER_THAN = 305, /* TOKEN_GREATER_THAN */
|
||||||
|
TOKEN_LESS_THAN = 306, /* TOKEN_LESS_THAN */
|
||||||
|
TOKEN_EXPONENTIAL = 307, /* TOKEN_EXPONENTIAL */
|
||||||
|
TOKEN_DISPLAY = 308 /* 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 */
|
||||||
126
lab-5/utest.h
126
lab-5/utest.h
|
|
@ -255,8 +255,8 @@ UTEST_C_FUNC __declspec(dllimport) int __stdcall QueryPerformanceFrequency(
|
||||||
static void __cdecl f(void); \
|
static void __cdecl f(void); \
|
||||||
UTEST_INITIALIZER_BEGIN_DISABLE_WARNINGS \
|
UTEST_INITIALIZER_BEGIN_DISABLE_WARNINGS \
|
||||||
__pragma(comment(linker, "/include:" UTEST_SYMBOL_PREFIX #f "_")) \
|
__pragma(comment(linker, "/include:" UTEST_SYMBOL_PREFIX #f "_")) \
|
||||||
UTEST_C_FUNC __declspec(allocate(".CRT$XCU")) void(__cdecl * \
|
UTEST_C_FUNC \
|
||||||
f##_)(void) = f; \
|
__declspec(allocate(".CRT$XCU")) void(__cdecl * f##_)(void) = f; \
|
||||||
UTEST_INITIALIZER_END_DISABLE_WARNINGS \
|
UTEST_INITIALIZER_END_DISABLE_WARNINGS \
|
||||||
static void __cdecl f(void)
|
static void __cdecl f(void)
|
||||||
#else
|
#else
|
||||||
|
|
@ -321,22 +321,32 @@ static UTEST_INLINE void *utest_realloc(void *const pointer, size_t new_size) {
|
||||||
void *const new_pointer = realloc(pointer, new_size);
|
void *const new_pointer = realloc(pointer, new_size);
|
||||||
|
|
||||||
if (UTEST_NULL == new_pointer) {
|
if (UTEST_NULL == new_pointer) {
|
||||||
free(new_pointer);
|
free(pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new_pointer;
|
return new_pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prevent 64-bit integer overflow when computing a timestamp by using a trick
|
||||||
|
// from Sokol:
|
||||||
|
// https://github.com/floooh/sokol/blob/189843bf4f86969ca4cc4b6d94e793a37c5128a7/sokol_time.h#L204
|
||||||
|
static UTEST_INLINE utest_int64_t utest_mul_div(const utest_int64_t value,
|
||||||
|
const utest_int64_t numer,
|
||||||
|
const utest_int64_t denom) {
|
||||||
|
const utest_int64_t q = value / denom;
|
||||||
|
const utest_int64_t r = value % denom;
|
||||||
|
return q * numer + r * numer / denom;
|
||||||
|
}
|
||||||
|
|
||||||
static UTEST_INLINE utest_int64_t utest_ns(void) {
|
static UTEST_INLINE utest_int64_t utest_ns(void) {
|
||||||
#if defined(_MSC_VER) || defined(__MINGW64__) || defined(__MINGW32__)
|
#if defined(_MSC_VER) || defined(__MINGW64__) || defined(__MINGW32__)
|
||||||
utest_large_integer counter;
|
utest_large_integer counter;
|
||||||
utest_large_integer frequency;
|
utest_large_integer frequency;
|
||||||
QueryPerformanceCounter(&counter);
|
QueryPerformanceCounter(&counter);
|
||||||
QueryPerformanceFrequency(&frequency);
|
QueryPerformanceFrequency(&frequency);
|
||||||
return UTEST_CAST(utest_int64_t,
|
return utest_mul_div(counter.QuadPart, 1000000000, frequency.QuadPart);
|
||||||
(counter.QuadPart * 1000000000) / frequency.QuadPart);
|
|
||||||
#elif defined(__linux__) && defined(__STRICT_ANSI__)
|
#elif defined(__linux__) && defined(__STRICT_ANSI__)
|
||||||
return UTEST_CAST(utest_int64_t, clock()) * 1000000000 / CLOCKS_PER_SEC;
|
return utest_mul_div(clock(), 1000000000, CLOCKS_PER_SEC);
|
||||||
#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
|
#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
|
||||||
defined(__NetBSD__) || defined(__DragonFly__) || defined(__sun__) || \
|
defined(__NetBSD__) || defined(__DragonFly__) || defined(__sun__) || \
|
||||||
defined(__HAIKU__)
|
defined(__HAIKU__)
|
||||||
|
|
@ -447,6 +457,15 @@ struct utest_type_deducer final {
|
||||||
static void _(const T t);
|
static void _(const T t);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <> struct utest_type_deducer<char, false> {
|
||||||
|
static void _(const char c) {
|
||||||
|
if (std::is_signed<decltype(c)>::value) {
|
||||||
|
UTEST_PRINTF("%d", static_cast<int>(c));
|
||||||
|
} else {
|
||||||
|
UTEST_PRINTF("%u", static_cast<unsigned int>(c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
template <> struct utest_type_deducer<signed char, false> {
|
template <> struct utest_type_deducer<signed char, false> {
|
||||||
static void _(const signed char c) {
|
static void _(const signed char c) {
|
||||||
UTEST_PRINTF("%d", static_cast<int>(c));
|
UTEST_PRINTF("%d", static_cast<int>(c));
|
||||||
|
|
@ -512,6 +531,10 @@ template <> struct utest_type_deducer<unsigned long long, false> {
|
||||||
static void _(const unsigned long long i) { UTEST_PRINTF("%llu", i); }
|
static void _(const unsigned long long i) { UTEST_PRINTF("%llu", i); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <> struct utest_type_deducer<bool, false> {
|
||||||
|
static void _(const bool i) { UTEST_PRINTF(i ? "true" : "false"); }
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T> struct utest_type_deducer<const T *, false> {
|
template <typename T> struct utest_type_deducer<const T *, false> {
|
||||||
static void _(const T *t) {
|
static void _(const T *t) {
|
||||||
UTEST_PRINTF("%p", static_cast<void *>(const_cast<T *>(t)));
|
UTEST_PRINTF("%p", static_cast<void *>(const_cast<T *>(t)));
|
||||||
|
|
@ -528,6 +551,12 @@ template <typename T> struct utest_type_deducer<T, true> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <> struct utest_type_deducer<std::nullptr_t, false> {
|
||||||
|
static void _(std::nullptr_t t) {
|
||||||
|
UTEST_PRINTF("%p", static_cast<void *>(t));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(const T t) {
|
UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(const T t) {
|
||||||
utest_type_deducer<T>::_(t);
|
utest_type_deducer<T>::_(t);
|
||||||
|
|
@ -626,24 +655,23 @@ utest_type_printer(long long unsigned int i) {
|
||||||
!(defined(__MINGW32__) || defined(__MINGW64__)) || \
|
!(defined(__MINGW32__) || defined(__MINGW64__)) || \
|
||||||
defined(__TINYC__)
|
defined(__TINYC__)
|
||||||
#define utest_type_printer(val) \
|
#define utest_type_printer(val) \
|
||||||
UTEST_PRINTF(_Generic((val), signed char \
|
UTEST_PRINTF( \
|
||||||
: "%d", unsigned char \
|
_Generic((val), \
|
||||||
: "%u", short \
|
signed char: "%d", \
|
||||||
: "%d", unsigned short \
|
unsigned char: "%u", \
|
||||||
: "%u", int \
|
short: "%d", \
|
||||||
: "%d", long \
|
unsigned short: "%u", \
|
||||||
: "%ld", long long \
|
int: "%d", \
|
||||||
: "%lld", unsigned \
|
long: "%ld", \
|
||||||
: "%u", unsigned long \
|
long long: "%lld", \
|
||||||
: "%lu", unsigned long long \
|
unsigned: "%u", \
|
||||||
: "%llu", float \
|
unsigned long: "%lu", \
|
||||||
: "%f", double \
|
unsigned long long: "%llu", \
|
||||||
: "%f", long double \
|
float: "%f", \
|
||||||
: "%Lf", default \
|
double: "%f", \
|
||||||
: _Generic((val - val), ptrdiff_t \
|
long double: "%Lf", \
|
||||||
: "%p", default \
|
default: _Generic((val - val), ptrdiff_t: "%p", default: "undef")), \
|
||||||
: "undef")), \
|
(val))
|
||||||
(val))
|
|
||||||
#else
|
#else
|
||||||
/*
|
/*
|
||||||
we don't have the ability to print the values we got, so we create a macro
|
we don't have the ability to print the values we got, so we create a macro
|
||||||
|
|
@ -724,10 +752,12 @@ utest_strncpy_gcc(char *const dst, const char *const src, const size_t size) {
|
||||||
UTEST_AUTO(x) xEval = (x); \
|
UTEST_AUTO(x) xEval = (x); \
|
||||||
UTEST_AUTO(y) yEval = (y); \
|
UTEST_AUTO(y) yEval = (y); \
|
||||||
if (!((xEval)cond(yEval))) { \
|
if (!((xEval)cond(yEval))) { \
|
||||||
|
const char *const xAsString = #x; \
|
||||||
|
const char *const yAsString = #y; \
|
||||||
_Pragma("clang diagnostic pop") \
|
_Pragma("clang diagnostic pop") \
|
||||||
UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \
|
UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \
|
||||||
UTEST_PRINTF(" Expected : ("); \
|
UTEST_PRINTF(" Expected : ("); \
|
||||||
UTEST_PRINTF(#x ") " #cond " (" #y); \
|
UTEST_PRINTF("%s) " #cond " (%s", xAsString, yAsString); \
|
||||||
UTEST_PRINTF(")\n"); \
|
UTEST_PRINTF(")\n"); \
|
||||||
UTEST_PRINTF(" Actual : "); \
|
UTEST_PRINTF(" Actual : "); \
|
||||||
utest_type_printer(xEval); \
|
utest_type_printer(xEval); \
|
||||||
|
|
@ -751,9 +781,11 @@ utest_strncpy_gcc(char *const dst, const char *const src, const size_t size) {
|
||||||
UTEST_AUTO(x) xEval = (x); \
|
UTEST_AUTO(x) xEval = (x); \
|
||||||
UTEST_AUTO(y) yEval = (y); \
|
UTEST_AUTO(y) yEval = (y); \
|
||||||
if (!((xEval)cond(yEval))) { \
|
if (!((xEval)cond(yEval))) { \
|
||||||
|
const char *const xAsString = #x; \
|
||||||
|
const char *const yAsString = #y; \
|
||||||
UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \
|
UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \
|
||||||
UTEST_PRINTF(" Expected : ("); \
|
UTEST_PRINTF(" Expected : ("); \
|
||||||
UTEST_PRINTF(#x ") " #cond " (" #y); \
|
UTEST_PRINTF("%s) " #cond " (%s", xAsString, yAsString); \
|
||||||
UTEST_PRINTF(")\n"); \
|
UTEST_PRINTF(")\n"); \
|
||||||
UTEST_PRINTF(" Actual : "); \
|
UTEST_PRINTF(" Actual : "); \
|
||||||
utest_type_printer(xEval); \
|
utest_type_printer(xEval); \
|
||||||
|
|
@ -1130,7 +1162,7 @@ utest_strncpy_gcc(char *const dst, const char *const src, const size_t size) {
|
||||||
} \
|
} \
|
||||||
UTEST_INITIALIZER(utest_register_##SET##_##NAME) { \
|
UTEST_INITIALIZER(utest_register_##SET##_##NAME) { \
|
||||||
const size_t index = utest_state.tests_length++; \
|
const size_t index = utest_state.tests_length++; \
|
||||||
const char *name_part = #SET "." #NAME; \
|
const char name_part[] = #SET "." #NAME; \
|
||||||
const size_t name_size = strlen(name_part) + 1; \
|
const size_t name_size = strlen(name_part) + 1; \
|
||||||
char *name = UTEST_PTR_CAST(char *, malloc(name_size)); \
|
char *name = UTEST_PTR_CAST(char *, malloc(name_size)); \
|
||||||
utest_state.tests = UTEST_PTR_CAST( \
|
utest_state.tests = UTEST_PTR_CAST( \
|
||||||
|
|
@ -1138,13 +1170,19 @@ utest_strncpy_gcc(char *const dst, const char *const src, const size_t size) {
|
||||||
utest_realloc(UTEST_PTR_CAST(void *, utest_state.tests), \
|
utest_realloc(UTEST_PTR_CAST(void *, utest_state.tests), \
|
||||||
sizeof(struct utest_test_state_s) * \
|
sizeof(struct utest_test_state_s) * \
|
||||||
utest_state.tests_length)); \
|
utest_state.tests_length)); \
|
||||||
if (utest_state.tests) { \
|
if (utest_state.tests && name) { \
|
||||||
utest_state.tests[index].func = &utest_##SET##_##NAME; \
|
utest_state.tests[index].func = &utest_##SET##_##NAME; \
|
||||||
utest_state.tests[index].name = name; \
|
utest_state.tests[index].name = name; \
|
||||||
utest_state.tests[index].index = 0; \
|
utest_state.tests[index].index = 0; \
|
||||||
UTEST_SNPRINTF(name, name_size, "%s", name_part); \
|
UTEST_SNPRINTF(name, name_size, "%s", name_part); \
|
||||||
} else if (name) { \
|
} else { \
|
||||||
free(name); \
|
if (utest_state.tests) { \
|
||||||
|
free(utest_state.tests); \
|
||||||
|
utest_state.tests = NULL; \
|
||||||
|
} \
|
||||||
|
if (name) { \
|
||||||
|
free(name); \
|
||||||
|
} \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
UTEST_SURPRESS_WARNINGS_END \
|
UTEST_SURPRESS_WARNINGS_END \
|
||||||
|
|
@ -1178,7 +1216,7 @@ utest_strncpy_gcc(char *const dst, const char *const src, const size_t size) {
|
||||||
} \
|
} \
|
||||||
UTEST_INITIALIZER(utest_register_##FIXTURE##_##NAME) { \
|
UTEST_INITIALIZER(utest_register_##FIXTURE##_##NAME) { \
|
||||||
const size_t index = utest_state.tests_length++; \
|
const size_t index = utest_state.tests_length++; \
|
||||||
const char *name_part = #FIXTURE "." #NAME; \
|
const char name_part[] = #FIXTURE "." #NAME; \
|
||||||
const size_t name_size = strlen(name_part) + 1; \
|
const size_t name_size = strlen(name_part) + 1; \
|
||||||
char *name = UTEST_PTR_CAST(char *, malloc(name_size)); \
|
char *name = UTEST_PTR_CAST(char *, malloc(name_size)); \
|
||||||
utest_state.tests = UTEST_PTR_CAST( \
|
utest_state.tests = UTEST_PTR_CAST( \
|
||||||
|
|
@ -1186,12 +1224,18 @@ utest_strncpy_gcc(char *const dst, const char *const src, const size_t size) {
|
||||||
utest_realloc(UTEST_PTR_CAST(void *, utest_state.tests), \
|
utest_realloc(UTEST_PTR_CAST(void *, utest_state.tests), \
|
||||||
sizeof(struct utest_test_state_s) * \
|
sizeof(struct utest_test_state_s) * \
|
||||||
utest_state.tests_length)); \
|
utest_state.tests_length)); \
|
||||||
if (utest_state.tests) { \
|
if (utest_state.tests && name) { \
|
||||||
utest_state.tests[index].func = &utest_f_##FIXTURE##_##NAME; \
|
utest_state.tests[index].func = &utest_f_##FIXTURE##_##NAME; \
|
||||||
utest_state.tests[index].name = name; \
|
utest_state.tests[index].name = name; \
|
||||||
UTEST_SNPRINTF(name, name_size, "%s", name_part); \
|
UTEST_SNPRINTF(name, name_size, "%s", name_part); \
|
||||||
} else if (name) { \
|
} else { \
|
||||||
free(name); \
|
if (utest_state.tests) { \
|
||||||
|
free(utest_state.tests); \
|
||||||
|
utest_state.tests = NULL; \
|
||||||
|
} \
|
||||||
|
if (name) { \
|
||||||
|
free(name); \
|
||||||
|
} \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
UTEST_SURPRESS_WARNINGS_END \
|
UTEST_SURPRESS_WARNINGS_END \
|
||||||
|
|
@ -1226,7 +1270,7 @@ utest_strncpy_gcc(char *const dst, const char *const src, const size_t size) {
|
||||||
utest_uint64_t iUp; \
|
utest_uint64_t iUp; \
|
||||||
for (i = 0; i < (INDEX); i++) { \
|
for (i = 0; i < (INDEX); i++) { \
|
||||||
const size_t index = utest_state.tests_length++; \
|
const size_t index = utest_state.tests_length++; \
|
||||||
const char *name_part = #FIXTURE "." #NAME; \
|
const char name_part[] = #FIXTURE "." #NAME; \
|
||||||
const size_t name_size = strlen(name_part) + 32; \
|
const size_t name_size = strlen(name_part) + 32; \
|
||||||
char *name = UTEST_PTR_CAST(char *, malloc(name_size)); \
|
char *name = UTEST_PTR_CAST(char *, malloc(name_size)); \
|
||||||
utest_state.tests = UTEST_PTR_CAST( \
|
utest_state.tests = UTEST_PTR_CAST( \
|
||||||
|
|
@ -1234,14 +1278,20 @@ utest_strncpy_gcc(char *const dst, const char *const src, const size_t size) {
|
||||||
utest_realloc(UTEST_PTR_CAST(void *, utest_state.tests), \
|
utest_realloc(UTEST_PTR_CAST(void *, utest_state.tests), \
|
||||||
sizeof(struct utest_test_state_s) * \
|
sizeof(struct utest_test_state_s) * \
|
||||||
utest_state.tests_length)); \
|
utest_state.tests_length)); \
|
||||||
if (utest_state.tests) { \
|
if (utest_state.tests && name) { \
|
||||||
utest_state.tests[index].func = &utest_i_##FIXTURE##_##NAME##_##INDEX; \
|
utest_state.tests[index].func = &utest_i_##FIXTURE##_##NAME##_##INDEX; \
|
||||||
utest_state.tests[index].index = i; \
|
utest_state.tests[index].index = i; \
|
||||||
utest_state.tests[index].name = name; \
|
utest_state.tests[index].name = name; \
|
||||||
iUp = UTEST_CAST(utest_uint64_t, i); \
|
iUp = UTEST_CAST(utest_uint64_t, i); \
|
||||||
UTEST_SNPRINTF(name, name_size, "%s/%" UTEST_PRIu64, name_part, iUp); \
|
UTEST_SNPRINTF(name, name_size, "%s/%" UTEST_PRIu64, name_part, iUp); \
|
||||||
} else if (name) { \
|
} else { \
|
||||||
free(name); \
|
if (utest_state.tests) { \
|
||||||
|
free(utest_state.tests); \
|
||||||
|
utest_state.tests = NULL; \
|
||||||
|
} \
|
||||||
|
if (name) { \
|
||||||
|
free(name); \
|
||||||
|
} \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue