commit b8350feec76cd459f94c1511783ceb2576ec84ed
parent 1d7fb22b9ff8207d7303b430311e7ba8d3963d57
Author: Christos Margiolis <christos@margiolis.net>
Date: Tue, 24 May 2022 00:43:10 +0300
almost
Diffstat:
5 files changed, 132 insertions(+), 122 deletions(-)
diff --git a/lex_yacc_compilers/part3/Makefile b/lex_yacc_compilers/part3/Makefile
@@ -2,7 +2,7 @@ all:
bison -d syntax.y
flex lex.l
cc syntax.tab.c lex.yy.c -lm -o uniclips
- ./uniclips input.txt
+ ./uniclips input.txt output.txt
clean:
rm -f *.yy.c *.output *.tab.c *.tab.h uniclips *.core
diff --git a/lex_yacc_compilers/part3/input.txt b/lex_yacc_compilers/part3/input.txt
@@ -1,31 +1,12 @@
-+1234
-50
--115
-3.14
--10.0
-+0.0001
-3.14e-10
-0e0
-static-facts
-MoveUp
-CUBES
-sum-1
-table
-pacman
-A-21-b
-?x
-?X
-?3
-?ad
-?X1b23
-?32AbC
-?ABcd1234de
-""
-"Test"
-"Hello world"
-"Mark said, \"Boo!\""
-; this is a comment
-ignore whitespace
-#unknown ?2 ? ?hello ?world
-deffacts defrule test
-2 + 2
+(printout "hello" "hello")
+(bind ?var 1)
+(bind ?var (+ 1 2))
+(test (= 1 2))
+(= 1 (+ 2 3))
+
+(defrule move-up
+ (+ 1 2)
+ (- 1 (+ 1 (* 1 2)))
+ (test (= 1 2))
+ ->
+ (printout "hello"))
diff --git a/lex_yacc_compilers/part3/lex.l b/lex_yacc_compilers/part3/lex.l
@@ -8,8 +8,8 @@
* Με βάση το μέρος Α2, υλοποιούμε τις κανονικές εκφράσεις και τις
* αντιστοιχούμε στα κατάλληλα tokens.
*/
-FUNC deffacts|defrule|test|bind|read|printout|quit|"+"|"-"|"*"|"/"|"="|"e"
-DELIM [ \t]+
+ARITH "+"|"-"|"*"|"/"|"="
+DELIM [ \t\n]+
INT 0|[+-]?[1-9]+[0-9]*
FLOAT [+-]?[0-9]+((\.[0-9]+)([eE][+-]?[0-9]*)?|([eE][+-]?[0-9]*)?)
STR \"[^\"\\]*(?:\\.[^\"\\]*)*\"
@@ -22,17 +22,24 @@ COMMENT ;.*
* οποίο ανήκει
*/
%%
-{FUNC} { yylval.sval = strdup(yytext); return FUNC; }
-{INT} { yylval.dval = strtod(yytext, NULL); return INT; }
-{FLOAT} { yylval.dval = strtod(yytext, NULL); return FLOAT; }
-{STR} { yylval.sval = strdup(yytext); return STR; }
-{DEFIN} { yylval.sval = strdup(yytext); return DEFIN; }
-{VAR} { yylval.sval = strdup(yytext); return VAR; }
+"deffacts" { return DEFFACTS; }
+"defrule" { return DEFRULE; }
+"bind" { return BIND; }
+"read" { return READ; }
+"printout" { return PRINT; }
+"test" { return TEST; }
+"=" { return COMP; }
"(" { return LPAR; }
")" { return RPAR; }
"->" { return ARROW; }
-\n { return NEWLINE; }
+{ARITH} { return ARITH; }
+{INT} { return INT; }
+{FLOAT} { return FLOAT;}
+{STR} { return STR; }
+{DEFIN} { return DEFIN; }
+{VAR} { return VAR; }
{DELIM} { /* ignore whitespace */ }
{COMMENT} { /* skip comments */ }
+"\n" { return NEWLINE; }
. { return UNKNOWN; }
%%
diff --git a/lex_yacc_compilers/part3/output.txt b/lex_yacc_compilers/part3/output.txt
@@ -0,0 +1,6 @@
+input.txt: success
+
+correct words: 0
+correct expressions: 12
+wrong words: 0
+wrong expressions: 0
diff --git a/lex_yacc_compilers/part3/syntax.y b/lex_yacc_compilers/part3/syntax.y
@@ -2,116 +2,132 @@
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
-#include <math.h>
+/* Silence warnings... */
extern int yylex(void);
-extern int yyparse(void);
+
+/* Input and output files. */
extern FILE *yyin, *yyout;
-extern char *yytext;
-double func(char *);
-double calc(char *, double, double);
+int cw = 0; /* correct words */
+int ce = 0; /* correct expressions */
+int ww = 0; /* wrong words */
+int we = 0; /* wrong expressions */
+
void yyerror(const char *);
%}
-%union {
- double dval;
- char *sval;
-}
-
-%token <sval> FUNC STR DEFIN VAR
-%token <dval> INT FLOAT
-%token NEWLINE UNKNOWN LPAR RPAR ARROW
-
-%type <dval> expr
+/* Tokens declared from flex. */
+%token DEFFACTS DEFRULE BIND READ PRINT TEST ARITH INT FLOAT COMP
+%token STR DEFIN VAR LPAR RPAR ARROW NEWLINE UNKNOWN
%start prog
%%
+/* Start here. */
prog:
- { printf("> "); }
- | prog expr NEWLINE { printf("%f\n> ", $2); }
+ | prog NEWLINE
+ | prog expr
;
-expr:
- INT { $$ = $1; }
- | FLOAT { $$ = $1; }
- | LPAR FUNC RPAR { $$ = func($2); }
- | LPAR FUNC expr expr RPAR { $$ = calc($2, $3, $4); }
- | error { yyerror("error"); }
+/*
+ * Declare numbers. Variables only accept numerical values so add them here as
+ * well.
+ */
+num:
+ INT
+ | FLOAT
+ | VAR
;
-%%
-double
-func(char *op)
-{
- double n;
- int rc;
-
- if (strcmp(op, "quit") == 0) {
- exit(0);
- } else if (strcmp(op, "read") == 0) {
- do {
- printf("read> ");
- rc = scanf("%lf", &n);
- (void)getchar();
- } while (rc != 1);
- return (n);
- }
+/* Accept any number of strings (for use in printout) */
+str:
+ STR
+ | str STR
+ ;
- yyerror("invalid expression");
- /* NOT REACHED */
- return (0);
-}
+/* (= (expr)) */
+cmp:
+ LPAR COMP expr expr RPAR
+ ;
-double
-calc(char *op, double arg1, double arg2)
-{
- if (strcmp(op, "+") == 0)
- return (arg1 + arg2);
- else if (strcmp(op, "-") == 0)
- return (arg1 - arg2);
- else if (strcmp(op, "*") == 0)
- return (arg1 * arg2);
- else if (strcmp(op, "/") == 0) {
- if (arg2 == 0)
- yyerror("cannot divide by 0");
- return (arg1 / arg2);
- }
- else if (strcmp(op, "e") == 0)
- return (pow(arg1, arg2));
- else if (strcmp(op, "=") == 0)
- return (arg1 == arg2);
+/* (test (= (expr))) */
+test:
+ LPAR TEST cmp RPAR
+ ;
- yyerror("invalid expression");
- /* NOT REACHED */
- return (0);
-}
+/* (prinout (str)...) */
+print:
+ LPAR PRINT str RPAR
+ ;
+fact:
+ expr
+ | fact expr
+ ;
+
+/* We match expressions here. */
+expr:
+ num /* numbers */
+ | cmp { ce++; } /* comparisons */
+ | test { ce++; } /* test keyword */
+ | print { ce++; } /* (printout "str"...) */
+ | LPAR READ RPAR { ce++; } /* (read) */
+ | LPAR ARITH expr expr RPAR { ce++; } /* (arithmetic_op (expr)...) */
+ | LPAR BIND VAR expr RPAR { ce++; } /* (bind ?var (expr)) */
+ | LPAR DEFFACTS DEFIN fact RPAR { ce++; } /* (deffacts DEF facts...) */
+ /* (defrule DEF
+ * (facts)
+ * ...
+ * (test)
+ * ->
+ * (printout))
+ */
+ | LPAR DEFRULE DEFIN fact test ARROW print RPAR { ce++; }
+ | error { we++; if (ce > 0) ce--; }
+ ;
+%%
+
+/* Print errors. */
void
yyerror(const char *s)
{
fprintf(stderr, "%s\n", s);
- exit(1);
}
int
main(int argc, char *argv[])
{
- /*if (argc < 2) {*/
- /*fprintf(stderr, "usage: %s input [output]\n", *argv);*/
- /*return (-1);*/
- /*}*/
- /*if ((yyin = fopen(argv[1], "r")) == NULL)*/
- /*err(1, "fopen(%s)", argv[1]);*/
- /*if (argc == 3 && (yyout = fopen(argv[2], "w")) == NULL)*/
- /*err(1, "fopen(%s)", argv[2]);*/
-
- if (yyparse() == 0)
- fprintf(stderr, "success\n");
- else
- fprintf(stderr, "failure\n");
+ /* We need at least 1 input and 1 output file... */
+ if (argc < 3) {
+ fprintf(stderr, "usage: %s input... output\n", *argv);
+ return (-1);
+ }
+
+ /* Open last file as output. */
+ if ((yyout = fopen(argv[--argc], "w")) == NULL)
+ err(1, "fopen(%s)", argv[argc]);
+
+ /* Parse all input files in reverse order. */
+ while (argc-- > 1) {
+ if ((yyin = fopen(argv[argc], "r")) == NULL)
+ err(1, "fopen(%s)", argv[argc]);
+ /* Parse file */
+ if (yyparse() == 0)
+ fprintf(yyout, "%s: success\n", argv[argc]);
+ else
+ fprintf(yyout, "%s: failure\n", argv[argc]);
+ fclose(yyin);
+ }
+
+ /* Print results. */
+ fprintf(yyout, "\n");
+ fprintf(yyout, "correct words: %d\n", cw);
+ fprintf(yyout, "correct expressions: %d\n", ce);
+ fprintf(yyout, "wrong words: %d\n", ww);
+ fprintf(yyout, "wrong expressions: %d\n", we);
+
+ fclose(yyout);
return (0);
}