From 9414bcfba7ea9244e49ab845c891d07451113da3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Sj=C3=B6lund?= <martin.sjolund@liu.se> Date: Thu, 31 Oct 2019 11:11:20 +0100 Subject: [PATCH] Swapped positions of lab1 and lab2 --- doc/{Doxyfile.lab1 => Doxyfile.lab2} | 4 +- doc/Makefile | 2 +- doc/source/lab1.rst | 185 ++++++++++----------------- doc/source/lab2.rst | 185 +++++++++++++++++---------- lab1/Makefile | 56 +++++--- {lab2 => lab1}/Makefile.dependencies | 0 lab1/main.cc | 155 +++++++++++++++++----- {lab2 => lab1}/scanner.h | 0 {lab2 => lab1}/scanner.l | 0 {lab2 => lab1}/test/comments | 0 {lab2 => lab1}/test/identifiers | 0 {lab2 => lab1}/test/numbers | 0 lab2/Makefile | 56 +++----- lab1/lab1.cc => lab2/lab2.cc | 2 +- lab1/lab1.hh => lab2/lab2.hh | 0 {lab1 => lab2}/lex.cc | 0 {lab1 => lab2}/lex.hh | 0 lab2/main.cc | 155 +++++----------------- 18 files changed, 400 insertions(+), 400 deletions(-) rename doc/{Doxyfile.lab1 => Doxyfile.lab2} (99%) rename {lab2 => lab1}/Makefile.dependencies (100%) rename {lab2 => lab1}/scanner.h (100%) rename {lab2 => lab1}/scanner.l (100%) rename {lab2 => lab1}/test/comments (100%) rename {lab2 => lab1}/test/identifiers (100%) rename {lab2 => lab1}/test/numbers (100%) rename lab1/lab1.cc => lab2/lab2.cc (98%) rename lab1/lab1.hh => lab2/lab2.hh (100%) rename {lab1 => lab2}/lex.cc (100%) rename {lab1 => lab2}/lex.hh (100%) diff --git a/doc/Doxyfile.lab1 b/doc/Doxyfile.lab2 similarity index 99% rename from doc/Doxyfile.lab1 rename to doc/Doxyfile.lab2 index ac83bcd..7dddc4e 100644 --- a/doc/Doxyfile.lab1 +++ b/doc/Doxyfile.lab2 @@ -8,7 +8,7 @@ PROJECT_NAME = TDDD55 PROJECT_NUMBER = PROJECT_BRIEF = "TDDD55 Labs" PROJECT_LOGO = -OUTPUT_DIRECTORY = doxygen-lab1 +OUTPUT_DIRECTORY = doxygen-lab2 CREATE_SUBDIRS = NO ALLOW_UNICODE_NAMES = NO OUTPUT_LANGUAGE = English @@ -111,7 +111,7 @@ WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- -INPUT = ../lab1 +INPUT = ../lab2 INPUT_ENCODING = UTF-8 FILE_PATTERNS = *.c \ *.cc \ diff --git a/doc/Makefile b/doc/Makefile index 859e735..792d427 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -22,7 +22,7 @@ html: Makefile doxygen-lab1/xml/index.xml doxygen-lab3/xml/index.xml clean: rm -rf "$(BUILDDIR)" doxygen-lab* -doxygen-lab1/xml/index.xml: Doxyfile.lab1 +doxygen-lab2/xml/index.xml: Doxyfile.lab2 doxygen $< doxygen-lab3/xml/index.xml: Doxyfile.lab3 doxygen $< diff --git a/doc/source/lab1.rst b/doc/source/lab1.rst index b1f02ed..3c49785 100644 --- a/doc/source/lab1.rst +++ b/doc/source/lab1.rst @@ -1,134 +1,79 @@ -.. _lab1: +Lab 2: Scanner Specification +============================ -Lab 1: Attribute Grammars and Top-Down Parsing -============================================== +The scanner is the part of the compiler responsible for grouping characters in the input stream into tokens which are used by the parser. +A typical scanner for a programming language will recognize tokens such as reserved words, identifiers, numeric constants, strings and operators. -.. default-domain:: cpp +One of the simplest ways of implementing a scanner is to use a scanner generator. +There are numerous such tools available. For this exercise you will use ``flex``, which stands for "Fast lex". -Although not as flexible as bottom-up parsers, top-down parsers can easily be implemented by hand, and as such they may be more convenient than a bottom-up parsers. -In this exercise you will specify a language of mathematical expressions using an attribute grammar, and then write a top-down parser to calculate the value of expressions in the language. +Using flex +---------- -The language consists of numbers, symbolic constants, single-argument functions, one unary and five binary operators. -A grammar for the language is given below, but this grammar is not suitable for implementation using a top-down technique since it is ambiguous and contains left recursion. +Full documentation for flex is available as a man page. +Just type ``man flex`` at a Unix prompt to see the documentation. +There are a few differences between ``lex`` and ``flex``, but not too many. -.. code-block :: bnf +The Generated Scanner +--------------------- - <S> ::= <E> <end of line> <S> // Single Expression - | <end of line> // No more input - <E> ::= <E> "+" <E> // Addition - | <E> "-" <E> // Subtraction - | <E> "*" <E> // Multiplication - | <E> "/" <E> // Division - | <E> "^" <E> // Exponentiation - | "-" <E> // Unary minus - | "(" <E> ")" // Grouping - | id "(" <E> ")" // Function call - | id // Symbolic constant - | num // Numeric value +When you compile a scanner specification using flex, a function named ``yylex`` is generated. +The default definition of this function takes no arguments and returns an integer, which represents the scanned token. + +Tokens are usually numbered from 257 and up, since that allows the scanner to return any single character as a token. +In ``scanner.l`` the final rule uses this feature; any unmatched characters are returned as tokens. + +The generated scanner also includes a number of important global variables and utility functions. +The ones that you will encounter are the variables ``yylineno``, ``yyin``, ``yytext`` and the function ``yyterminate``. + +yylineno + This variable holds the number of the current line of input. + It is useful for error reporting, but slows the scanner down somewhat, so in order to use it, it has to be explicitly enabled using command-line options or the ``yylineno`` declaration in the scanner specification. + +yyin + This variable holds the file pointer from which ``yylex`` reads its input. + +yytext + This is a character array containing the characters that were recognized as a token. + +yyterminate + This function terminates the scanning process and causes ``yylex`` to return 0. + It can be called in any action, and is the default action at the end of file. + +The Tokens +---------- + +Your scanner shall skip comments, both single-line C++ comments and multi line C-style comments. +If the scanner sees ``/*`` within a C comment it has to print a warning message. +If the end of file is encountered within a C style comment, your scanner must print an error message and then terminate. + +Floating-point numbers + Consist of an integer part followed by a period, a decimal part and an exponent. + The integer and decimal parts are simply sequences of digits. + The exponent part consists of the character ``E`` followed by an optional sign and a sequence of digits. + Either the integer or the decimal part (or both) must be given. + The exponent is optional. + If the integer part and exponent are both given, the decimal point and decimal part are optional. + These are some valid floating-point numbers: ``1.1``, ``.1``, ``1.``, ``1E2``, ``2E-3``, ``.1E-4``. + When your scanner recognizes a floating-point number it should return ``REAL``. +Integers + Are simply sequences of digits that are not part of identifiers or floating-point numbers. + When your scanner recognizes an integer it should return ``INTEGER``. +Identifiers + Must start with a letter, followed by any number of digits, letters or underscore characters. + When your scanner recognizes an identifier it should return ``ID``. Requirements ------------ -Rewrite the grammar in the previous section so that the precedence and associativity of all operators becomes obvious. -Your grammar may contain left recursion. -The operator precedence is unary negation before exponentiation before multiplication and division, before addition and subtraction. -Addition, subtraction, multiplication and division are left associative. -Exponentiation is right-associative. - -Eliminate left recursion from your grammar and revise it so it is suitable for implementation in a predictive top-down parser. - -Implement your attribute grammar in a C++ class named :class:`Parser`. -The :class:`Parser` class should contain a method named :func:`Parser::Parse` that returns the value of a single statement in the language. -Your interpreter should understand the following symbolic constants and functions: - -.. list-table :: - - * - pi - - 3.14159265 - * - e - - 2.71828183 - * - `log() <https://linux.die.net/man/3/log>`_ - - Natural logarithm - * - `log10() <https://linux.die.net/man/3/log10>`_ - - Base 10 logarithm - * - `exp() <https://linux.die.net/man/3/exp>`_ - - Powers of e - * - `sin() <https://linux.die.net/man/3/sin>`_ - - Sine - * - `cos() <https://linux.die.net/man/3/cos>`_ - - Cosine - * - `tan() <https://linux.die.net/man/3/tan>`_ - - Tangent - * - `arcsin() <https://linux.die.net/man/3/arcsin>`_ - - Arc sine - * - `arccos() <https://linux.die.net/man/3/arccos>`_ - - Arc cosine - * - `arctan() <https://linux.die.net/man/3/arctan>`_ - - Arc tangent - -All the functions are available in the standard math library. -See the Unix manual pages for details. - -Implement error recovery in your parser. -The simplest form of error recovery is to scan tokens to the end of a line and then resume parsing. -Feel free to implement a smarter error recovery strategy. +You are to finish the scanner specification in ``scanner.l`` by adding rules for C and C++ style comments, identifiers, integers and reals. +Compile your scanner using the command ``make scanner``. +This generates a program named scanner, which you can use to test your scanner. +Run your scanner on the files in lab1/test and check that it generates the correct output. Hand in the following - * Printouts of all the files you modified or created. - * Answers to the questions in the next section. - * Test data that show that the program works as specified. - Be sure to test error recovery, both from parser and scanner errors. - Be sure to check that error recovery does not interfere with the next input line. - Check that precedence and associativity rules are followed. + * The scanner specification, with your changes clearly marked. + * Test data that show that the scanner works as specified. Demonstrate your solution to your lab assistant during a laboratory session. -Send an e-mail (one e-mail per group) with your modified code and answers to the questions to the same assistant, put TDDD55, assignment number and your LiU logins in the e-mail subject line. - -Questions ---------- - -#. Define a regular expression for numeric constants. - It should allow integers, numbers with a fractional part and numbers with an exponent. - A number containing a decimal point must have at least one digit before or after the decimal point (or both). - The exponent may have a sign, plus or minus, and is always an integer. - - .. list-table :: - :header-rows: 1 - - * - Allowed - - Not allowed - * - ``1234`` - - ``A123`` - * - ``3.14`` - - ``.`` - * - ``.112`` - - ``112.a`` - * - ``112.`` - - ``1E2.3`` - * - ``12.34`` - - ``2.3e3.`` - * - ``34E-23`` - - ``23E 54`` - * - ``34.E+3`` - - - * - ``2.2e5`` - - -#. Construct a DFA that accepts the same language as the regular expression you defined in the previous question. - Suggest how to implement a scanner based on your DFA. - -Supporting Programs -------------------- - -The files ``lab1.cc`` and ``lab1.hh`` contain a skeleton for the parser class and a class called :class:`Trace` that can be used to trace invocation of functions. -See the :func:`Parser::Parse` method for an example of how to use it. -Objects of the class print an entry message when created and an exit message when destroyed. - -The files ``lex.cc`` and ``lex.hh`` contain a scanner class. -To use it create an object of type :class:`Scanner` and call its :func:`Scanner::Scan` method to get a token. -Tokens returned are of type :class:`Token`. -See the comments in ``lex.hh`` for a description of how they work. - -The file ``main.cc`` contains a sample main program. -You may have to modify it depending on how you choose to report errors from your parser. -If the scanner encounters an error it will throw an object of type :class`ScannerError`. -Your main program should catch this exception (the sample main program does), print an error message (you can print a :class:`ScannerError` object using stream operators) and then perform error recovery. +Send an e-mail (one e-mail per group) with your modified code to the same assistant, put TDDD55, assignment number and your LiU logins in the e-mail subject line. diff --git a/doc/source/lab2.rst b/doc/source/lab2.rst index 580d2b2..af8bcc8 100644 --- a/doc/source/lab2.rst +++ b/doc/source/lab2.rst @@ -1,79 +1,134 @@ -Lab 2: Scanner Specification -============================ +.. _lab2: -The scanner is the part of the compiler responsible for grouping characters in the input stream into tokens which are used by the parser. -A typical scanner for a programming language will recognize tokens such as reserved words, identifiers, numeric constants, strings and operators. +Lab 2: Attribute Grammars and Top-Down Parsing +============================================== -One of the simplest ways of implementing a scanner is to use a scanner generator. -There are numerous such tools available. For this exercise you will use ``flex``, which stands for "Fast lex". +.. default-domain:: cpp -Using flex ----------- +Although not as flexible as bottom-up parsers, top-down parsers can easily be implemented by hand, and as such they may be more convenient than a bottom-up parsers. +In this exercise you will specify a language of mathematical expressions using an attribute grammar, and then write a top-down parser to calculate the value of expressions in the language. -Full documentation for flex is available as a man page. -Just type ``man flex`` at a Unix prompt to see the documentation. -There are a few differences between ``lex`` and ``flex``, but not too many. +The language consists of numbers, symbolic constants, single-argument functions, one unary and five binary operators. +A grammar for the language is given below, but this grammar is not suitable for implementation using a top-down technique since it is ambiguous and contains left recursion. -The Generated Scanner ---------------------- +.. code-block :: bnf -When you compile a scanner specification using flex, a function named ``yylex`` is generated. -The default definition of this function takes no arguments and returns an integer, which represents the scanned token. - -Tokens are usually numbered from 257 and up, since that allows the scanner to return any single character as a token. -In ``scanner.l`` the final rule uses this feature; any unmatched characters are returned as tokens. - -The generated scanner also includes a number of important global variables and utility functions. -The ones that you will encounter are the variables ``yylineno``, ``yyin``, ``yytext`` and the function ``yyterminate``. - -yylineno - This variable holds the number of the current line of input. - It is useful for error reporting, but slows the scanner down somewhat, so in order to use it, it has to be explicitly enabled using command-line options or the ``yylineno`` declaration in the scanner specification. - -yyin - This variable holds the file pointer from which ``yylex`` reads its input. - -yytext - This is a character array containing the characters that were recognized as a token. - -yyterminate - This function terminates the scanning process and causes ``yylex`` to return 0. - It can be called in any action, and is the default action at the end of file. - -The Tokens ----------- - -Your scanner shall skip comments, both single-line C++ comments and multi line C-style comments. -If the scanner sees ``/*`` within a C comment it has to print a warning message. -If the end of file is encountered within a C style comment, your scanner must print an error message and then terminate. - -Floating-point numbers - Consist of an integer part followed by a period, a decimal part and an exponent. - The integer and decimal parts are simply sequences of digits. - The exponent part consists of the character ``E`` followed by an optional sign and a sequence of digits. - Either the integer or the decimal part (or both) must be given. - The exponent is optional. - If the integer part and exponent are both given, the decimal point and decimal part are optional. - These are some valid floating-point numbers: ``1.1``, ``.1``, ``1.``, ``1E2``, ``2E-3``, ``.1E-4``. - When your scanner recognizes a floating-point number it should return ``REAL``. -Integers - Are simply sequences of digits that are not part of identifiers or floating-point numbers. - When your scanner recognizes an integer it should return ``INTEGER``. -Identifiers - Must start with a letter, followed by any number of digits, letters or underscore characters. - When your scanner recognizes an identifier it should return ``ID``. + <S> ::= <E> <end of line> <S> // Single Expression + | <end of line> // No more input + <E> ::= <E> "+" <E> // Addition + | <E> "-" <E> // Subtraction + | <E> "*" <E> // Multiplication + | <E> "/" <E> // Division + | <E> "^" <E> // Exponentiation + | "-" <E> // Unary minus + | "(" <E> ")" // Grouping + | id "(" <E> ")" // Function call + | id // Symbolic constant + | num // Numeric value Requirements ------------ -You are to finish the scanner specification in ``scanner.l`` by adding rules for C and C++ style comments, identifiers, integers and reals. -Compile your scanner using the command ``make scanner``. -This generates a program named scanner, which you can use to test your scanner. -Run your scanner on the files in lab2/test and check that it generates the correct output. +Rewrite the grammar in the previous section so that the precedence and associativity of all operators becomes obvious. +Your grammar may contain left recursion. +The operator precedence is unary negation before exponentiation before multiplication and division, before addition and subtraction. +Addition, subtraction, multiplication and division are left associative. +Exponentiation is right-associative. + +Eliminate left recursion from your grammar and revise it so it is suitable for implementation in a predictive top-down parser. + +Implement your attribute grammar in a C++ class named :class:`Parser`. +The :class:`Parser` class should contain a method named :func:`Parser::Parse` that returns the value of a single statement in the language. +Your interpreter should understand the following symbolic constants and functions: + +.. list-table :: + + * - pi + - 3.14159265 + * - e + - 2.71828183 + * - `log() <https://linux.die.net/man/3/log>`_ + - Natural logarithm + * - `log10() <https://linux.die.net/man/3/log10>`_ + - Base 10 logarithm + * - `exp() <https://linux.die.net/man/3/exp>`_ + - Powers of e + * - `sin() <https://linux.die.net/man/3/sin>`_ + - Sine + * - `cos() <https://linux.die.net/man/3/cos>`_ + - Cosine + * - `tan() <https://linux.die.net/man/3/tan>`_ + - Tangent + * - `arcsin() <https://linux.die.net/man/3/arcsin>`_ + - Arc sine + * - `arccos() <https://linux.die.net/man/3/arccos>`_ + - Arc cosine + * - `arctan() <https://linux.die.net/man/3/arctan>`_ + - Arc tangent + +All the functions are available in the standard math library. +See the Unix manual pages for details. + +Implement error recovery in your parser. +The simplest form of error recovery is to scan tokens to the end of a line and then resume parsing. +Feel free to implement a smarter error recovery strategy. Hand in the following - * The scanner specification, with your changes clearly marked. - * Test data that show that the scanner works as specified. + * Printouts of all the files you modified or created. + * Answers to the questions in the next section. + * Test data that show that the program works as specified. + Be sure to test error recovery, both from parser and scanner errors. + Be sure to check that error recovery does not interfere with the next input line. + Check that precedence and associativity rules are followed. Demonstrate your solution to your lab assistant during a laboratory session. -Send an e-mail (one e-mail per group) with your modified code to the same assistant, put TDDD55, assignment number and your LiU logins in the e-mail subject line. +Send an e-mail (one e-mail per group) with your modified code and answers to the questions to the same assistant, put TDDD55, assignment number and your LiU logins in the e-mail subject line. + +Questions +--------- + +#. Define a regular expression for numeric constants. + It should allow integers, numbers with a fractional part and numbers with an exponent. + A number containing a decimal point must have at least one digit before or after the decimal point (or both). + The exponent may have a sign, plus or minus, and is always an integer. + + .. list-table :: + :header-rows: 1 + + * - Allowed + - Not allowed + * - ``1234`` + - ``A123`` + * - ``3.14`` + - ``.`` + * - ``.112`` + - ``112.a`` + * - ``112.`` + - ``1E2.3`` + * - ``12.34`` + - ``2.3e3.`` + * - ``34E-23`` + - ``23E 54`` + * - ``34.E+3`` + - + * - ``2.2e5`` + - +#. Construct a DFA that accepts the same language as the regular expression you defined in the previous question. + Suggest how to implement a scanner based on your DFA. + +Supporting Programs +------------------- + +The files ``lab2.cc`` and ``lab2.hh`` contain a skeleton for the parser class and a class called :class:`Trace` that can be used to trace invocation of functions. +See the :func:`Parser::Parse` method for an example of how to use it. +Objects of the class print an entry message when created and an exit message when destroyed. + +The files ``lex.cc`` and ``lex.hh`` contain a scanner class. +To use it create an object of type :class:`Scanner` and call its :func:`Scanner::Scan` method to get a token. +Tokens returned are of type :class:`Token`. +See the comments in ``lex.hh`` for a description of how they work. + +The file ``main.cc`` contains a sample main program. +You may have to modify it depending on how you choose to report errors from your parser. +If the scanner encounters an error it will throw an object of type :class`ScannerError`. +Your main program should catch this exception (the sample main program does), print an error message (you can print a :class:`ScannerError` object using stream operators) and then perform error recovery. diff --git a/lab1/Makefile b/lab1/Makefile index d4b2b1e..5616a35 100644 --- a/lab1/Makefile +++ b/lab1/Makefile @@ -1,16 +1,40 @@ -CC = g++ -CCFLAGS = -g -LDFLAGS = - -lab1 : lex.o main.o lab1.o - $(CC) -o lab1 $(CCFLAGS) $(LDFLAGS) lex.o main.o lab1.o - -lex.o: lex.hh lex.cc - $(CC) $(CFLAGS) -c lex.cc -lab1.o: lab1.hh lex.hh lab1.cc - $(CC) $(CFLAGS) -c lab1.cc -main.o: lab1.hh lex.hh main.cc - $(CC) $(CFLAGS) -c main.cc - -clean: - rm *.o lab1 +CC = g++ +CFLAGS = -ggdb3 -Wall -Woverloaded-virtual +#CC = CC +#CFLAGS = -g +p +w +GCFLAGS = -g +LDFLAGS = +DPFLAGS = -MM + +SOURCES = scanner.cc main.cc +HEADERS = scanner.h +OBJECTS = $(SOURCES:%.cc=%.o) +OUTFILE = scanner + +DPFILE = Makefile.dependencies + +FLEX = flex + +all : $(OUTFILE) + +$(OUTFILE) : $(OBJECTS) + $(CC) -o $(OUTFILE) $(OBJECTS) $(LDFLAGS) + +scanner.cc : scanner.l + $(FLEX) scanner.l + +scanner.o : scanner.cc + $(CC) $(GCFLAGS) -c $< + +.cc.o: $(DPFILE) + $(CC) $(CFLAGS) -c $< + +clean : + rm -f $(OBJECTS) $(OUTFILE) core *~ scanner.cc $(DPFILE) + touch $(DPFILE) + + +$(DPFILE) depend : $(SOURCES) $(HEADERS) + $(CC) $(DPFLAGS) $(CFLAGS) $(SOURCES) > $(DPFILE) + +include $(DPFILE) diff --git a/lab2/Makefile.dependencies b/lab1/Makefile.dependencies similarity index 100% rename from lab2/Makefile.dependencies rename to lab1/Makefile.dependencies diff --git a/lab1/main.cc b/lab1/main.cc index f0fd8f5..216ced2 100644 --- a/lab1/main.cc +++ b/lab1/main.cc @@ -1,35 +1,120 @@ -#include <iostream> -#include <stdlib.h> - -#include "lab1.hh" -#include "lex.hh" - -int main(void) -{ - Parser parser; - double val; - - while (1) - { - try - { - cout << "Expression: " << flush; - val = parser.Parse(); - cout << "Result: " << val << '\n' << flush; - } - catch (ScannerError& e) - { - cerr << e << '\n' << flush; - parser.Recover(); - } - catch (ParserError) - { - parser.Recover(); - } - catch (ParserEndOfFile) - { - cerr << "End of file\n" << flush; - exit(0); - } - } -} +#include <iostream> +#include <iomanip> +#include <stdio.h> +#include <stdlib.h> + +#include "scanner.h" + +using namespace std; + +typedef struct +{ + int token; + char *name; +} tTokenName; + + +tTokenName tokens[] = {{ FUNCTION, "FUNCTION" }, + { ID, "ID" }, + { DECLARE, "DECLARE" }, + { ARRAY, "ARRAY" }, + { INTEGER, "INTEGER" }, + { OF, "OF" }, + { REAL, "REAL" }, + { XBEGIN, "XBEGIN" }, + { XEND, "XEND" }, + { IF, "IF" }, + { THEN, "THEN" }, + { ELSE, "ELSE" }, + { WHILE, "WHILE" }, + { DO, "DO" }, + { ASSIGN, "ASSIGN" }, + { RETURN, "RETURN" }, + { GE, "GE" }, + { LE, "LE" }, + { EQ, "EQ" }, + { NE, "NE" }, + { TRUE, "TRUE" }, + { FALSE, "FALSE" }, + { PROGRAM, "PROGRAM" }, + { ELSEIF, "ELSEIF" }, + { NOT, "NOT" }, + { AND, "AND" }, + { OR, "OR" }, + { UMINUS, "UMINUS" }}; + +int numTokens = sizeof(tokens)/sizeof(*tokens); + + +ostream& PrintToken(ostream& o, int token) +{ + int i; + extern char *yytext; + + for (i = 0; i < numTokens; i++) + { + if (token == tokens[i].token) + { + o << tokens[i].name << " \'" << yytext << "\'"; + return o; + } + } + + o << '\'' << (unsigned char)token << '\''; + + return o; +} + +// omanip<int> Token(int t) +// { +// return omanip<int>(&PrintToken, t); +// } + +int main(int argc, char **argv) +{ + int token; + extern FILE *yyin; + extern int yylex(); + + /* + * Open the input file, if any + */ + + switch(argc) + { + case 1: + yyin = stdin; + break; + case 2: + yyin = fopen(argv[1], "r"); + if (yyin == NULL) + { + perror(argv[1]); + exit(1); + } + break; + default: + cerr << "Usage: " << argv[0] << " [ filename ]\n"; + exit(1); + } + + + /* + * Loop for as long as there are tokens + */ + + while ((token = yylex()) != 0) + { + cout << "Scanned "; PrintToken(cout, token); cout << '\n' << flush; + } + + cout << "End of file\n"; + exit(0); +} + +void yyerror(char *msg) +{ + extern int yylineno; + + cerr << "Error at line " << yylineno << ": " << msg << '\n' << flush; +} diff --git a/lab2/scanner.h b/lab1/scanner.h similarity index 100% rename from lab2/scanner.h rename to lab1/scanner.h diff --git a/lab2/scanner.l b/lab1/scanner.l similarity index 100% rename from lab2/scanner.l rename to lab1/scanner.l diff --git a/lab2/test/comments b/lab1/test/comments similarity index 100% rename from lab2/test/comments rename to lab1/test/comments diff --git a/lab2/test/identifiers b/lab1/test/identifiers similarity index 100% rename from lab2/test/identifiers rename to lab1/test/identifiers diff --git a/lab2/test/numbers b/lab1/test/numbers similarity index 100% rename from lab2/test/numbers rename to lab1/test/numbers diff --git a/lab2/Makefile b/lab2/Makefile index 5616a35..fd270a3 100644 --- a/lab2/Makefile +++ b/lab2/Makefile @@ -1,40 +1,16 @@ -CC = g++ -CFLAGS = -ggdb3 -Wall -Woverloaded-virtual -#CC = CC -#CFLAGS = -g +p +w -GCFLAGS = -g -LDFLAGS = -DPFLAGS = -MM - -SOURCES = scanner.cc main.cc -HEADERS = scanner.h -OBJECTS = $(SOURCES:%.cc=%.o) -OUTFILE = scanner - -DPFILE = Makefile.dependencies - -FLEX = flex - -all : $(OUTFILE) - -$(OUTFILE) : $(OBJECTS) - $(CC) -o $(OUTFILE) $(OBJECTS) $(LDFLAGS) - -scanner.cc : scanner.l - $(FLEX) scanner.l - -scanner.o : scanner.cc - $(CC) $(GCFLAGS) -c $< - -.cc.o: $(DPFILE) - $(CC) $(CFLAGS) -c $< - -clean : - rm -f $(OBJECTS) $(OUTFILE) core *~ scanner.cc $(DPFILE) - touch $(DPFILE) - - -$(DPFILE) depend : $(SOURCES) $(HEADERS) - $(CC) $(DPFLAGS) $(CFLAGS) $(SOURCES) > $(DPFILE) - -include $(DPFILE) +CC = g++ +CCFLAGS = -g +LDFLAGS = + +lab2 : lex.o main.o lab2.o + $(CC) -o lab2 $(CCFLAGS) $(LDFLAGS) lex.o main.o lab2.o + +lex.o: lex.hh lex.cc + $(CC) $(CFLAGS) -c lex.cc +lab2.o: lab2.hh lex.hh lab2.cc + $(CC) $(CFLAGS) -c lab2.cc +main.o: lab2.hh lex.hh main.cc + $(CC) $(CFLAGS) -c main.cc + +clean: + rm *.o lab2 diff --git a/lab1/lab1.cc b/lab2/lab2.cc similarity index 98% rename from lab1/lab1.cc rename to lab2/lab2.cc index d18474e..dfbe98a 100644 --- a/lab1/lab1.cc +++ b/lab2/lab2.cc @@ -1,4 +1,4 @@ -#include "lab1.hh" +#include "lab2.hh" // diff --git a/lab1/lab1.hh b/lab2/lab2.hh similarity index 100% rename from lab1/lab1.hh rename to lab2/lab2.hh diff --git a/lab1/lex.cc b/lab2/lex.cc similarity index 100% rename from lab1/lex.cc rename to lab2/lex.cc diff --git a/lab1/lex.hh b/lab2/lex.hh similarity index 100% rename from lab1/lex.hh rename to lab2/lex.hh diff --git a/lab2/main.cc b/lab2/main.cc index 216ced2..32a5458 100644 --- a/lab2/main.cc +++ b/lab2/main.cc @@ -1,120 +1,35 @@ -#include <iostream> -#include <iomanip> -#include <stdio.h> -#include <stdlib.h> - -#include "scanner.h" - -using namespace std; - -typedef struct -{ - int token; - char *name; -} tTokenName; - - -tTokenName tokens[] = {{ FUNCTION, "FUNCTION" }, - { ID, "ID" }, - { DECLARE, "DECLARE" }, - { ARRAY, "ARRAY" }, - { INTEGER, "INTEGER" }, - { OF, "OF" }, - { REAL, "REAL" }, - { XBEGIN, "XBEGIN" }, - { XEND, "XEND" }, - { IF, "IF" }, - { THEN, "THEN" }, - { ELSE, "ELSE" }, - { WHILE, "WHILE" }, - { DO, "DO" }, - { ASSIGN, "ASSIGN" }, - { RETURN, "RETURN" }, - { GE, "GE" }, - { LE, "LE" }, - { EQ, "EQ" }, - { NE, "NE" }, - { TRUE, "TRUE" }, - { FALSE, "FALSE" }, - { PROGRAM, "PROGRAM" }, - { ELSEIF, "ELSEIF" }, - { NOT, "NOT" }, - { AND, "AND" }, - { OR, "OR" }, - { UMINUS, "UMINUS" }}; - -int numTokens = sizeof(tokens)/sizeof(*tokens); - - -ostream& PrintToken(ostream& o, int token) -{ - int i; - extern char *yytext; - - for (i = 0; i < numTokens; i++) - { - if (token == tokens[i].token) - { - o << tokens[i].name << " \'" << yytext << "\'"; - return o; - } - } - - o << '\'' << (unsigned char)token << '\''; - - return o; -} - -// omanip<int> Token(int t) -// { -// return omanip<int>(&PrintToken, t); -// } - -int main(int argc, char **argv) -{ - int token; - extern FILE *yyin; - extern int yylex(); - - /* - * Open the input file, if any - */ - - switch(argc) - { - case 1: - yyin = stdin; - break; - case 2: - yyin = fopen(argv[1], "r"); - if (yyin == NULL) - { - perror(argv[1]); - exit(1); - } - break; - default: - cerr << "Usage: " << argv[0] << " [ filename ]\n"; - exit(1); - } - - - /* - * Loop for as long as there are tokens - */ - - while ((token = yylex()) != 0) - { - cout << "Scanned "; PrintToken(cout, token); cout << '\n' << flush; - } - - cout << "End of file\n"; - exit(0); -} - -void yyerror(char *msg) -{ - extern int yylineno; - - cerr << "Error at line " << yylineno << ": " << msg << '\n' << flush; -} +#include <iostream> +#include <stdlib.h> + +#include "lab2.hh" +#include "lex.hh" + +int main(void) +{ + Parser parser; + double val; + + while (1) + { + try + { + cout << "Expression: " << flush; + val = parser.Parse(); + cout << "Result: " << val << '\n' << flush; + } + catch (ScannerError& e) + { + cerr << e << '\n' << flush; + parser.Recover(); + } + catch (ParserError) + { + parser.Recover(); + } + catch (ParserEndOfFile) + { + cerr << "End of file\n" << flush; + exit(0); + } + } +} -- GitLab