⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 elex.texi

📁 用于词法分析的词法分析器
💻 TEXI
📖 第 1 页 / 共 5 页
字号:
this grammar you need a scanner that matches the following symbols: `+',`-', `/', `*', `mod', `(', `)', plus @var{variable} and @var{number}(which are defined above as a regular expressions).  A @var{variable} isany string of letters or underscores, and a @var{number} can be anythingfrom an integer to a floating point value with an exponent.So, the first thing you need for the calculator is a scanner that canrecognize these symbols --- this is where @var{Elex} comes in.@c ----------------------------------------------------------------------@node       The Scanner Script, Testing the Script, The Calculator, An Example@section    The Scanner Script@cindex scanner script, example@cindex example, scanner script@cindex CalcScanner.elxAfter much head-scratching and cursing over the flippant prose in themanual, you finally produce an @var{Elex} scanner script that you thinkwill work.  The complete script is listed below (it's called@file{demo/CalcScanner.elx} in the @var{Elex} distribution).The comments (lines starting with `#') within the script give a briefdescription of the meaning of each part.  @xref{Scanner Scripts} for thedetails.@example# This is the start of the scanner definition.scanner CalcScanner@group  # This section tells the code generator to declare these names to be  # unique integer constants that will be used to represent each  # symbol.symbols  SymNumber SymVariable SymMod SymPlus SymMinus SymStar SymSlash  SymLBracket SymRBracket@end group@group  # This section is used to define symbolic expressions that can be  # used in later regular expressions.defines  number = "0-9+"@end groupbegin  # This is the main section, composed of a number of productions that  # each define a symbol.  Each production is of the form  #  #  on [@var{productionName}] "@var{regexp}"  #  <  #    @var{code to be executed on a match of regexp}  #  >  #  # The productionName part is used to give a meaningful name to the  # production.  If no name is given, the production's position in the  # script is used as the name (the first production is numbered 1).@group  # Matches numbers like 1, -1.2, +1.1e10, -10e-2  on Number "<number>(\.<number>)?([eE][\+\-]?<number>)?"  <    // SymNumber, like all the constants used in return statements    // below, appears in the `symbols' section and is declared by the    // code generator.    return SymNumber;  >@end group@group  # Matches variable names beginning with a letter, followed by zero  # or more letters or underscores.  on Variable "[a-zA-Z][a-zA-Z_]*"  <    return SymVariable;  >@end group@group  # This matches `mod' as a keyword.  Note that while the Variable  # production above also matches 'mod', this production has  # precedence because it comes later in the script.  on Mod "mod"  <    return SymMod;  >@end group  on Plus "\+"  <    return SymPlus;  >  on Minus "\-"  <    return SymMinus;  >  on Star "\*"  <    return SymStar;  >  on Slash "/"  <    return SymSlash;  >  on LBracket "\("  <    return SymLBracket;  >  on RBracket "\)"  <    return SymRBracket;  >@group  # This production causes the scanner to ignore whitespace.  on WhiteSpace "[ \t\n]+"  <    return SymNULL;  >@end group@group  # The error production gets matched when the scanner reads something  # that cannot be matched by any other production.  The default  # behavior if this production does not exist is to raise `invalid  # symbol' error.  This default behavior is overridden if this  # production returns SymNULL, but will still happen if the  # production returns SymERROR.  on error  <    // This production has no effect, since returning SymERROR means    // error is handed as usual.    return SymERROR;  >@end groupend@end example@c ----------------------------------------------------------------------@node       Testing the Script, Generating the Scanner, The Scanner Script, An Example@section    Testing the Script@cindex testing example@cindex debugging example@cindex example, debugging@cindex example, debugging output@cindex CalcScanner.elx, debuggingNow you've written a script it's a well-known rule that you and thecomputer will have different ideas what the script actually does.Typically you don't find this out until you compile the code and test itin program, but @var{Elex} has a way of testing the regular expressionsbefore you generate any code.  You don't have to have written any codeat all to use this feature.To test the @file{CalcScanner.elx} script, run the @var{Elex} frontend in debug mode like this:@example> elex -d CalcScanner.elx@end exampleIf the script compiles OK, the @var{Elex} script debugger runs eachline of the standard input through the scanner, matching symbols andprinting them in this format:@example@var{row}:@var{column} @var{production_name} "@var{matched_text}"@end example@var{row} and @var{column} indicate where the symbol was found,@var{production_name} is the name you gave the production and@var{matched_text} is the actual text matched for the production.Error symbols have a production name of `<error>'.Below is the transcript of a session with the @var{Elex} debugger andthe @file{CalcScanner.elx} script (bold lines are those entered by theuser):@cartouche@example@group> @b{elex -d CalcScanner.elx} @b{1.2 3.14e-2 8+a_variable/(mod)}0:0: Number: "1.2"0:3: WhiteSpace: " "0:4: Number: "3.14e-2"0:11: WhiteSpace: " "0:12: Number: "8"0:13: Plus: "+"0:14: Variable: "a_variable"0:24: Slash: "/"0:25: LBracket: "("0:26: Mod: "mod"@b{123.2e 1. !#$%^&}0:29: RBracket: ")"0:30: WhiteSpace: ""1:0: Number: "123.2"1:5: Variable: "e"1:6: WhiteSpace: " "1:7: Number: "1"1:8: <Error>: "."1:9: WhiteSpace: " "1:10: <Error>: "!#$%^&"1:17: WhiteSpace: ""@end group@end example@end cartoucheYou might notice that the `)' ending the first line of user input doesnot get matched until after the second line has been entered.  Thisdue to the @var{Elex} scanner engine's backtracking design(@pxref{Backtracking Scanners}).@c ----------------------------------------------------------------------@node       Generating the Scanner, Using the Scanner, Testing the Script, An Example@section    Generating the Scanner@cindex generating C++ code@cindex CalcScanner.h, listing@cindex ElexScanner.h@cindex ElexScanner@cindex CalcScanner, class@cindex C++ code, generating with Elex@cindex example, generating a C++ scanner@cindex example, C++ scanner implementationNow you're happy with the scanner script, it's time to use @var{Elex} togenerate some code:@example> elex CalcScanner.elx@end exampleIf no errors occur you'll get two output files, @file{ElexScanner.h} and@file{ElexScanner.cpp}.  These files define a C++ class called@code{CalcScanner} which implements the scanner defined by the script.@file{ElexScanner.h} will look something like this (minus the comments):@example#include <cppscan/ElexScanner.h>class CalcScanner : public ElexScanner@{public:  // These are from the script `symbols' section.  enum @{SymLBracket, SymMinus, SymMod, SymNumber, SymPlus,        SymRBracket, SymSlash, SymStar, SymVariable@};  // These are used internally.  enum @{ProdNumber, ProdVariable, ProdMod, ProdPlus, ProdMinus,        ProdStar, ProdSlash, ProdLBracket, ProdRBracket,        ProdWhiteSpace, Proderror@};  // Create a CalcScanner reading from `i'.  CalcScanner (XInputStream &i);  // Called with one of the ProdXXX constants to invoke the code for  // the associated production.  virtual int invokeProduction (int prod);@group  // Production handler member functions generated from the code  // fragments in the script.  int prodNumber ();  int prodVariable ();  int prodMod ();  int prodPlus ();  int prodMinus ();  int prodStar ();  int prodSlash ();  int prodLBracket ();  int prodRBracket ();  int prodWhiteSpace ();  int proderror ();@end group@};@end example@c ----------------------------------------------------------------------@node       Using the Scanner,  , Generating the Scanner, An Example@section    Using the Scanner@cindex compiling a scanner@cindex using a scanner@cindex scanner, compiling@cindex C++ scanner, compiling@cindex CalcScanner, compiling@cindex example, using a scanner@cindex example, compiling a scannerTo use the scanner in an application, you simply create an instance ofthe scanner class, passing it an @code{XInputStream} object thatencapsulates an @code{istream}.  You can then use the @code{getNext ()}function to read each symbol, the @code{getSymbol ()} and @code{getText()} functions to read the symbol and matched text and the @code{eof ()}function to test for the end of input.  For example:@example@groupXInputStream str (cin);    // read from standard inputCalcScanner scanner (str); // create the scannerdo@{  scanner.getNext ();      // read next symbol  cout << "Symbol: : " << scanner.getSymbol () << endl;  cout << "Text: : "   << scanner.getText () << endl;@} while (!scanner.eof ())@end group@end exampleTo compile the C++ calculator application you need to include@file{CalcScanner.h} and ensure that the appropriate @var{Elex} headerfiles and libraries are accessible to the compiler.  The @var{Elex}C++ header files can be found in the @file{cppscan} directory and the@var{Elex} library is called @file{lib/elex.a}, so the commands tocompile and link the @file{calc.cpp} application are:@example@group> g++ -c calc.cpp CalcParser.cpp CalcScanner.cpp -I$ELEX_HOME/cppscan> g++ -o calc calc.o CalcParser.o CalcScanner.o $ELEX_HOME/lib/elex.a

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -