Skip to content
Snippets Groups Projects
Verified Commit 9414bcfb authored by Martin Sjölund's avatar Martin Sjölund
Browse files

Swapped positions of lab1 and lab2

parent 6bd3dd3c
No related branches found
No related tags found
No related merge requests found
...@@ -8,7 +8,7 @@ PROJECT_NAME = TDDD55 ...@@ -8,7 +8,7 @@ PROJECT_NAME = TDDD55
PROJECT_NUMBER = PROJECT_NUMBER =
PROJECT_BRIEF = "TDDD55 Labs" PROJECT_BRIEF = "TDDD55 Labs"
PROJECT_LOGO = PROJECT_LOGO =
OUTPUT_DIRECTORY = doxygen-lab1 OUTPUT_DIRECTORY = doxygen-lab2
CREATE_SUBDIRS = NO CREATE_SUBDIRS = NO
ALLOW_UNICODE_NAMES = NO ALLOW_UNICODE_NAMES = NO
OUTPUT_LANGUAGE = English OUTPUT_LANGUAGE = English
...@@ -111,7 +111,7 @@ WARN_LOGFILE = ...@@ -111,7 +111,7 @@ WARN_LOGFILE =
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options related to the input files # Configuration options related to the input files
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
INPUT = ../lab1 INPUT = ../lab2
INPUT_ENCODING = UTF-8 INPUT_ENCODING = UTF-8
FILE_PATTERNS = *.c \ FILE_PATTERNS = *.c \
*.cc \ *.cc \
......
...@@ -22,7 +22,7 @@ html: Makefile doxygen-lab1/xml/index.xml doxygen-lab3/xml/index.xml ...@@ -22,7 +22,7 @@ html: Makefile doxygen-lab1/xml/index.xml doxygen-lab3/xml/index.xml
clean: clean:
rm -rf "$(BUILDDIR)" doxygen-lab* rm -rf "$(BUILDDIR)" doxygen-lab*
doxygen-lab1/xml/index.xml: Doxyfile.lab1 doxygen-lab2/xml/index.xml: Doxyfile.lab2
doxygen $< doxygen $<
doxygen-lab3/xml/index.xml: Doxyfile.lab3 doxygen-lab3/xml/index.xml: Doxyfile.lab3
doxygen $< doxygen $<
.. _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. Using flex
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. ----------
The language consists of numbers, symbolic constants, single-argument functions, one unary and five binary operators. Full documentation for flex is available as a man page.
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. 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 When you compile a scanner specification using flex, a function named ``yylex`` is generated.
| <end of line> // No more input The default definition of this function takes no arguments and returns an integer, which represents the scanned token.
<E> ::= <E> "+" <E> // Addition
| <E> "-" <E> // Subtraction Tokens are usually numbered from 257 and up, since that allows the scanner to return any single character as a token.
| <E> "*" <E> // Multiplication In ``scanner.l`` the final rule uses this feature; any unmatched characters are returned as tokens.
| <E> "/" <E> // Division
| <E> "^" <E> // Exponentiation The generated scanner also includes a number of important global variables and utility functions.
| "-" <E> // Unary minus The ones that you will encounter are the variables ``yylineno``, ``yyin``, ``yytext`` and the function ``yyterminate``.
| "(" <E> ")" // Grouping
| id "(" <E> ")" // Function call yylineno
| id // Symbolic constant This variable holds the number of the current line of input.
| num // Numeric value 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 Requirements
------------ ------------
Rewrite the grammar in the previous section so that the precedence and associativity of all operators becomes obvious. You are to finish the scanner specification in ``scanner.l`` by adding rules for C and C++ style comments, identifiers, integers and reals.
Your grammar may contain left recursion. Compile your scanner using the command ``make scanner``.
The operator precedence is unary negation before exponentiation before multiplication and division, before addition and subtraction. This generates a program named scanner, which you can use to test your scanner.
Addition, subtraction, multiplication and division are left associative. Run your scanner on the files in lab1/test and check that it generates the correct output.
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 Hand in the following
* Printouts of all the files you modified or created. * The scanner specification, with your changes clearly marked.
* Answers to the questions in the next section. * Test data that show that the scanner works as specified.
* 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. 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. 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.
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.
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. Lab 2: Attribute Grammars and Top-Down Parsing
A typical scanner for a programming language will recognize tokens such as reserved words, identifiers, numeric constants, strings and operators. ==============================================
One of the simplest ways of implementing a scanner is to use a scanner generator. .. default-domain:: cpp
There are numerous such tools available. For this exercise you will use ``flex``, which stands for "Fast lex".
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. The language consists of numbers, symbolic constants, single-argument functions, one unary and five binary operators.
Just type ``man flex`` at a Unix prompt to see the documentation. 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.
There are a few differences between ``lex`` and ``flex``, but not too many.
The Generated Scanner .. code-block :: bnf
---------------------
When you compile a scanner specification using flex, a function named ``yylex`` is generated. <S> ::= <E> <end of line> <S> // Single Expression
The default definition of this function takes no arguments and returns an integer, which represents the scanned token. | <end of line> // No more input
<E> ::= <E> "+" <E> // Addition
Tokens are usually numbered from 257 and up, since that allows the scanner to return any single character as a token. | <E> "-" <E> // Subtraction
In ``scanner.l`` the final rule uses this feature; any unmatched characters are returned as tokens. | <E> "*" <E> // Multiplication
| <E> "/" <E> // Division
The generated scanner also includes a number of important global variables and utility functions. | <E> "^" <E> // Exponentiation
The ones that you will encounter are the variables ``yylineno``, ``yyin``, ``yytext`` and the function ``yyterminate``. | "-" <E> // Unary minus
| "(" <E> ")" // Grouping
yylineno | id "(" <E> ")" // Function call
This variable holds the number of the current line of input. | id // Symbolic constant
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. | num // Numeric value
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 Requirements
------------ ------------
You are to finish the scanner specification in ``scanner.l`` by adding rules for C and C++ style comments, identifiers, integers and reals. Rewrite the grammar in the previous section so that the precedence and associativity of all operators becomes obvious.
Compile your scanner using the command ``make scanner``. Your grammar may contain left recursion.
This generates a program named scanner, which you can use to test your scanner. The operator precedence is unary negation before exponentiation before multiplication and division, before addition and subtraction.
Run your scanner on the files in lab2/test and check that it generates the correct output. 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 Hand in the following
* The scanner specification, with your changes clearly marked. * Printouts of all the files you modified or created.
* Test data that show that the scanner works as specified. * 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. 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.
CC = g++ CC = g++
CCFLAGS = -g CFLAGS = -ggdb3 -Wall -Woverloaded-virtual
LDFLAGS = #CC = CC
#CFLAGS = -g +p +w
lab1 : lex.o main.o lab1.o GCFLAGS = -g
$(CC) -o lab1 $(CCFLAGS) $(LDFLAGS) lex.o main.o lab1.o LDFLAGS =
DPFLAGS = -MM
lex.o: lex.hh lex.cc
$(CC) $(CFLAGS) -c lex.cc SOURCES = scanner.cc main.cc
lab1.o: lab1.hh lex.hh lab1.cc HEADERS = scanner.h
$(CC) $(CFLAGS) -c lab1.cc OBJECTS = $(SOURCES:%.cc=%.o)
main.o: lab1.hh lex.hh main.cc OUTFILE = scanner
$(CC) $(CFLAGS) -c main.cc
DPFILE = Makefile.dependencies
clean:
rm *.o lab1 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)
File moved
#include <iostream> #include <iostream>
#include <stdlib.h> #include <iomanip>
#include <stdio.h>
#include "lab1.hh" #include <stdlib.h>
#include "lex.hh"
#include "scanner.h"
int main(void)
{ using namespace std;
Parser parser;
double val; typedef struct
{
while (1) int token;
{ char *name;
try } tTokenName;
{
cout << "Expression: " << flush;
val = parser.Parse(); tTokenName tokens[] = {{ FUNCTION, "FUNCTION" },
cout << "Result: " << val << '\n' << flush; { ID, "ID" },
} { DECLARE, "DECLARE" },
catch (ScannerError& e) { ARRAY, "ARRAY" },
{ { INTEGER, "INTEGER" },
cerr << e << '\n' << flush; { OF, "OF" },
parser.Recover(); { REAL, "REAL" },
} { XBEGIN, "XBEGIN" },
catch (ParserError) { XEND, "XEND" },
{ { IF, "IF" },
parser.Recover(); { THEN, "THEN" },
} { ELSE, "ELSE" },
catch (ParserEndOfFile) { WHILE, "WHILE" },
{ { DO, "DO" },
cerr << "End of file\n" << flush; { ASSIGN, "ASSIGN" },
exit(0); { 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;
}
File moved
File moved
File moved
File moved
File moved
CC = g++ CC = g++
CFLAGS = -ggdb3 -Wall -Woverloaded-virtual CCFLAGS = -g
#CC = CC LDFLAGS =
#CFLAGS = -g +p +w
GCFLAGS = -g lab2 : lex.o main.o lab2.o
LDFLAGS = $(CC) -o lab2 $(CCFLAGS) $(LDFLAGS) lex.o main.o lab2.o
DPFLAGS = -MM
lex.o: lex.hh lex.cc
SOURCES = scanner.cc main.cc $(CC) $(CFLAGS) -c lex.cc
HEADERS = scanner.h lab2.o: lab2.hh lex.hh lab2.cc
OBJECTS = $(SOURCES:%.cc=%.o) $(CC) $(CFLAGS) -c lab2.cc
OUTFILE = scanner main.o: lab2.hh lex.hh main.cc
$(CC) $(CFLAGS) -c main.cc
DPFILE = Makefile.dependencies
clean:
FLEX = flex rm *.o lab2
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)
#include "lab1.hh" #include "lab2.hh"
// //
......
File moved
File moved
File moved
#include <iostream> #include <iostream>
#include <iomanip> #include <stdlib.h>
#include <stdio.h>
#include <stdlib.h> #include "lab2.hh"
#include "lex.hh"
#include "scanner.h"
int main(void)
using namespace std; {
Parser parser;
typedef struct double val;
{
int token; while (1)
char *name; {
} tTokenName; try
{
cout << "Expression: " << flush;
tTokenName tokens[] = {{ FUNCTION, "FUNCTION" }, val = parser.Parse();
{ ID, "ID" }, cout << "Result: " << val << '\n' << flush;
{ DECLARE, "DECLARE" }, }
{ ARRAY, "ARRAY" }, catch (ScannerError& e)
{ INTEGER, "INTEGER" }, {
{ OF, "OF" }, cerr << e << '\n' << flush;
{ REAL, "REAL" }, parser.Recover();
{ XBEGIN, "XBEGIN" }, }
{ XEND, "XEND" }, catch (ParserError)
{ IF, "IF" }, {
{ THEN, "THEN" }, parser.Recover();
{ ELSE, "ELSE" }, }
{ WHILE, "WHILE" }, catch (ParserEndOfFile)
{ DO, "DO" }, {
{ ASSIGN, "ASSIGN" }, cerr << "End of file\n" << flush;
{ RETURN, "RETURN" }, exit(0);
{ 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;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment