This commit is contained in:
Preston Carman 2024-10-17 11:07:48 -07:00
parent 303e16b851
commit 47d1e653ed
8 changed files with 1882 additions and 1 deletions

View File

@ -1 +1,14 @@
---
lab_3_tests:
stage: test
image: gitlab.cs.wallawalla.edu:5050/cs_department/docker-images/cpp
script:
- apt update
- apt install -y flex bison
- bison --version
- cd lab-3
- echo "Lab 3 - Flex"
- flex -o scanner.c scanner.flex
- echo "Lab 3 - Compile Tests"
- gcc main_test.c scanner.c -o scanner_test.out
- echo "Lab 3 - Run Tests"
- ./scanner_test.out

73
lab-3/README.md Normal file
View File

@ -0,0 +1,73 @@
# Flex Scanner
Create a scanner for your sample programs.
See the [example lab for Python](https://gitlab.cs.wallawalla.edu/cptr354/language-interpreter-lab-python).
## Language Scanner
Add the tokens needed to scan your sample code files.
In addition include the following:
* All the math operations (+,-,/,* etc.)
* All boolean expression (==,>,< etc.)
* All relational operators (not,and,or)
* ...
## Testing the Language Scanner
Write unit test for your sample code.
The sample program uses `utest.h` which is a simple c unit test framework.
The documentation can be found at <https://github.com/sheredom/utest.h>.
The `main.c` has been replaced with unit test code.
Your task is to create one unit test for each sample file.
When you submit the code to GitLab, the CI should automatically compile and run your test code.
To recieve full credit, the tests must pass when run through GitLab CI.
## Build Process
To build the `scanner.c` run the following **flex** command.
```sh
flex -o scanner.c scanner.flex
```
Then build the `main.c` and `scanner.c` using **gcc**.
```sh
gcc main_test.c scanner.c -o scanner_test.out
```
Then execute the test suite using `./scanner_test.out`.
```sh
./scanner_test.out
```
## Scanner Only
```sh
flex -o scanner.c scanner.flex
gcc main.c scanner.c -o scanner.out
./scanner.out
```
## Grading Rubric
The grading will be over the following categories.
Points Description
----------- ------------------------------------
30 points Tests for individual language tokens
10 points Ability to scan — Hello world
20 points Ability to scan — Quadratic equation
20 points Ability to scan — Integer sorting
20 points Passes continuous integration
## Turn In
Please submit the URL of your gitlab project to D2L's Brightspace with your report.
On gitlab update the `lab-3` folder to have your report and code snippets before the due date.

30
lab-3/main.c Normal file
View File

@ -0,0 +1,30 @@
#include "token.h"
#include <stdio.h>
#include <stdlib.h>
extern FILE *yyin;
extern int yylex();
extern char *yytext;
int main(int argc, char *argv[]) {
FILE *file;
const char *filename = "samples/hello.py"; // Default filename
// Check if a filename is provided as a command-line argument
if (argc > 1) {
filename = argv[1];
}
// Open the file
yyin = fopen(filename, "r");
if (!yyin) {
printf("could not open file!\n");
return 1;
}
while (1) {
token_t t = yylex();
if (t == TOKEN_EOF)
break;
printf("token: %d text: %s\n", t, yytext);
}
}

72
lab-3/main_test.c Normal file
View File

@ -0,0 +1,72 @@
#include "token.h"
// https://github.com/sheredom/utest.h/blob/master/utest.h
#include "utest.h"
#include <stdio.h>
typedef struct yy_buffer_state *YY_BUFFER_STATE;
extern void yyrestart(FILE * input_file);
extern YY_BUFFER_STATE yy_scan_buffer(char *str, int i);
extern void yy_delete_buffer(YY_BUFFER_STATE buffer);
extern FILE *yyin;
extern int yylex();
extern char *yytext;
UTEST_MAIN();
struct token_st {
token_t t;
char *p;
};
UTEST(scanner, identifier) {
token_t t;
// Must include the null character to terminate input
char string[] = "test\0";
YY_BUFFER_STATE buffer = yy_scan_buffer(string, sizeof(string));
ASSERT_EQ(TOKEN_IDENT, (t = yylex()));
ASSERT_STREQ("test", yytext);
ASSERT_EQ(TOKEN_EOF, (t = yylex()));
ASSERT_STREQ("", yytext);
yy_delete_buffer(buffer);
}
UTEST(scanner, assignment) {
token_t t;
// Must include the null character to terminate input
char string[] = "=\0";
YY_BUFFER_STATE buffer = yy_scan_buffer(string, sizeof(string));
ASSERT_EQ(TOKEN_ASSIGNMENT, (t = yylex()));
ASSERT_STREQ("=", yytext);
ASSERT_EQ(TOKEN_EOF, (t = yylex()));
ASSERT_STREQ("", yytext);
yy_delete_buffer(buffer);
}
UTEST(scanner, sample) {
struct token_st tokens[] = {
{TOKEN_IDENT, "answer"},
{TOKEN_ASSIGNMENT, "="},
{TOKEN_NUMBER, "2020"},
{TOKEN_ADD, "+"},
{TOKEN_NUMBER, "4"},
{TOKEN_EOF, ""}
};
yyin = fopen("samples/program.c", "r");
yyrestart(yyin);
ASSERT_TRUE(yyin);
int index = 0;
token_t t;
do {
ASSERT_EQ(tokens[index].t, (t = yylex()));
ASSERT_STREQ(tokens[index].p, yytext);
++index;
} while (t != TOKEN_EOF);
}

1
lab-3/samples/program.c Normal file
View File

@ -0,0 +1 @@
answer = 2020+4

15
lab-3/scanner.flex Normal file
View File

@ -0,0 +1,15 @@
%{
#include "token.h"
%}
DIGIT [0-9]
LETTER [a-zA-Z]
%%
(" "|\t|\n) /* skip whitespace */
\+ { return TOKEN_ADD; }
"=" { return TOKEN_ASSIGNMENT; }
while { return TOKEN_WHILE; }
{LETTER}+ { return TOKEN_IDENT; }
{DIGIT}+ { return TOKEN_NUMBER; }
. { return TOKEN_ERROR; }
%%
int yywrap() { return 1; }

9
lab-3/token.h Normal file
View File

@ -0,0 +1,9 @@
typedef enum {
TOKEN_EOF = 0,
TOKEN_WHILE,
TOKEN_ADD,
TOKEN_ASSIGNMENT,
TOKEN_IDENT,
TOKEN_NUMBER,
TOKEN_ERROR
} token_t;

1668
lab-3/utest.h Normal file

File diff suppressed because it is too large Load Diff