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

📄 pascals.txt

📁 pascals编译程序源代码及说明
💻 TXT
📖 第 1 页 / 共 5 页
字号:
   (4) repeat s until b
   (5) for i := a to b do s
   (6) for i := a downto b do s
   (7) case e of
          v1: s1;v2: s2; ... ;vn: sn
       end
   (1)     code (b)                 (2)     code (b)
           conditional jump to L            conditional jump to L 1
           code (s)                         code (sl)
        L: ...                              jump to L2
                                        L1: code (s2)
                                        L2: ...
   (3) L1: code (b)                 (4)  L: code (s)
           conditional jump to L2           code (b)
           code (s)                         conditional jump to L
           jump to L 1
       L2: ...
   (5)     load address i           (6)     load address i
           code (a)                         code (a)
           code (b)                         code (b)
           for1upL2                         for1downL2
       L1: code (s)                     L1: code (s)
           for2up L1                        for2down L1
       L2: ...                          L2: .,.
   (7)     code (e)
           search switchlist L
       Ll: code (sl)
           jump to K
       L2: code (s2)
           jump to K
       Ln: code (sn)
           jump to K
        L: (vl,Ll)
           (v2,L2)
           (vn,Ln)
        K: ...

   In the case of the for statement, the address of the control variable and the two
limit values are left on the stack during execution of the repeated statement. The
switch order used in the case statement performs a simple, linear search through the
switch list, comparing the value on top of the stack with entries vl...vn. If a match
vi is found, a jump to Li is executed.

4.3 Post-mortem dump

If interpretation of the code leads to an error condition, execution is terminated
and a symbolic post-mortem dump is generated. Detected error conditions are:

(a) division by zero,
(b) selector value of a case statement out of range,
(c) array index out of bounds,
(d) stack overflow,
(e) line limit exceeded (too many lines),
(f) output line too long, and
(g) attempt to read beyond the end of the input file.

   The post-mortem consists of a list of the currently active procedures with an
indication of their activation points, and (for each procedure) a list of its local variables
and their current values. In order to keep the amount of information reasonably
small, only unstructured variables are listed, as they usually contain the information
relevant for detecting the cause of a trap. An example of a dump follows:

   0  program run error (output);
   0    var i: integer; b: boolean; x: real;
   0
   0    functionf(m,n: integer): integer;
   0    begin f:= f(n, m mod n) end;
   9
   9  begin x:= 9.87654321; b:= true, i:= f(511,31)
   20 end.
  (eof)

   Halt at      6 because of division by 0
   f     called at       7
     n       =           0
     m       =           1
   f     called at       7
     n       =           1
     m       =          15
   f     called at       7
     n       =          15
     m       =          31
   f     called at      21
     n       =          31
     m       =         511
     x       =    9.8765432100000E+OOO
     b       =        true
     i       =        8506
           38 steps

                    5. The compiler

Pascal is a language that can be parsed with a lookahead of a single symbol. The
compiler therefore uses the simple and efficient method of top-down parsing with
one-symbol lookahead. It is organized as a set of procedures, each representing a
specific sentential construct and parsing goal. These procedures may activate each
other recursively, just as certain sentential constructs occur recursively. The parsers
obtain their input through a scanner called insymbol. This scanner reads the input

file character by character, and delivers the next Pascal symbol each time it is called.
For this purpose, the scanner requires a lookahead of one character. The total lookahead
of the compiler is therefore one symbol plus character. For further information
on the principles of operation of a top-down, recursive descent compiler the
reader is referred to Wirth[5].

   When working his way through the compiler listing, the reader is advised to start
with the scanner called insymbol. The next symbol read is assigned to the global
I variable sy (which represents the symbollookahead). The scanner receives its input
by calling procedure nextch, which assigns the next character read to the global
r variable ch (which represents the character lookahead). If an identifier is encountered,
the actual identifier is assigned to the global variance id, and if it is a
number, its value is assigned to the global variables inum or rnum. If the symbol is a
string, the string is directly assigned to the string table stab (note that strings may
occur only as parameters in write statements).

   The set of procedures used to parse and translate Pascal-S programs closely mirrors
the syntactic structure of the- language. The reader is advised to consult the
syntax diagrams, as they represent abstract flow-charts of the parser procedures. It
is useful to keep the following compiler excerpt in mind, which mirrors the way in
which the compiler is partitioned and exhibits the interdependence of the principal
procedures (see also the procedure-dependence diagram in the Appendix).

   block
   constant
      typ
   arraytyp
   parame terlist
   constantdeclaration
   typedeclaration
   variabledeclaration
   proceduredeclaration
   statement
      selector
      call
      expression
         simpleexpression
            term
               factor
               standard functions
      assignment
      compound statement
      if statement
      case statement
      repeat statement
      while statement
      for statement
      standard procedures

   Much effort is spent providing robustness against ill-formed input recovery and
obtaining sensible error diagnostics. To achieve this aim, a systematic approach to
syntax error handling is used [5, 6]. Its main principle is that each parser always
returns control after having advanced up to a symbol that may legally follow the
sentential construct that the parser is supposed to process. If the input program
contains errors, this goal is usually achieved by skipping text until such an acceptable
symbol is encountered. For this purposed, procedures skip and test are used.

   The scheme requires that each parser know the set of symbols that may legally
follow its sentential construct in the current context. To this aim, each parser is
provided with a parameter indicating that set of so-called follow symbols (called
fsys). This set is, however, augmented by certain key symbols which are never to be
ignored. Typically, these key symbols are those which head a specific sentential
construct, such as begin, if, type, etc. Hence, these parameters do not necessarily
specify legal follow symbols, but rather the symbols where a possible skip has to
terminate.

   The following test program shows the compiler's handling of syntactically illformed
texts. Adequate recovery from syntactic errors is indeed a crucial criterion
for a system to be used in an environment where errors occur frequently. A list of
brief explanations to the error numbers is included in the Appendix.

      0 program syntaxerror (output);
      0    const m = 10, n := 20
   ****                 ^14 ^16
      0    type t = array 1..10 of real;
   ****      ^14          ^11   ^12
      0         r := record x: real,
   ****            ^16             ^14
      0            b,c: boolean
      0         end
      0    var i: integer;
   ****      ^14
      0        p,q: boolean;x,y: real;;
   ****                               ^ 6
      0        i: integer, ch: char
   ****        ^ 1       ^14
      0        a: array (l..m) of integer;
   ****        ^14      ^ll   ^12
      0    const y = 3.14159;
   ****        ^56
      0 begin i := x m := i 
   ****              ^ 6
      3    if b do p=(porq);
   ****     ^14  ^52 ^51   ^14
     12    while j < 10
   ****          ^ 0
     14       begin k:= .5(x-y; y:=x)
   ****           ^35 ^14           ^ 6
     18       end
     19    if p then p = 1; else i := 2;
   ****     ^14        ^51     ^14
     24    repeat x := p + i*(x>y);
   ****                           ^33
     30       for x = 1 to q
   ****             ^18
     31          begin i:=a[2 I
   ****              ^19
     36    until i=j
   ****        ^28  ^ 0
     39    for j ;= 1 to n while x > 0 do
   ****      ^35               ^54
     50       begin a(j] :=a[j+1);read(i)
   ****              ^11     ^ 0 ^28 ^20
     59 end.
   ****    ^14
   program incomplete
   key words
           0 undef id
           1 multi def
           4 )
           6 syntax
           11 [
           12 ]
           14 ;
           16 =
           18 convar typ
           19 type
           20 prog.param
           28 no array
           33 arith type
           35 types
           51 :=
           52 then
           54 do
           56 begin

   The compiler can functionally be subdivided into two main parts: the part processing
declarations and the part processing statements and expressions. Their
common interface is the symbol table tab and further associated tables. They are
constructed by the declaration processing part, and constitute the necessary context
in which the program statements are to be compiled. Knowledge of the struc-
ture of these tables is therefore of fundamental importance. The key table is tab.
Each declared identifier causes one entry. All entries of identifiers local to the same
procedure (block) are linked together. Note that the compiler program is written
without using any dynamic structures and pointers. Hence, a linked chain is represented
by explicit array indices. The field called obi indicates whether the identifier
denotes a constant, a variable, a type, a procedure, or a function. Its type is specified
by the field called typo The meaning of the remaining fields varies according to
the object and type. If the type of an entry is an array type, then the ref field is an
index. to the table of array structures called aref; if it is a record type, the ref field
contains an index to the table of records and blocks called btab. The Boolean field
nonnal specifies whether an entry is an actual (normal) variable to be addressed
directly or a formal parameter to be addressed indirectly. The fields lev and adr
specify the address pair of a variable or procedure. If the entry denotes a constant
and the constant is of type integer, Boolean, or char, then the adr field indicates its
value. If its type is real, the adr field specifies an index of the table of real numbers
called rconst.

   The array table atab specifies for each array structure its index type and index
bounds, its element type (eltyp and elref, where the latter is used in analogy to the
field ref above), and its size in terms of storage elements. For the sake of convenience
only, the size of an element is also present, although it could easily be
derived via eltyp and elref.

   Each procedure and each record type defmition causes an entry in the table of
'blocks' called btab. It contains pointers to the last identifier (in tab) defmed local
I to the block and to the last parameter of the corresponding procedure. Note that all
previous entities can be accessed through the linked chain. Morever, the entry specifies
the storage size needed to represent the set of variables belonging to the respective
record of procedure.

   A sample program and the structure of the tables constructed during its compilation
are shown below. These tables are derived from the auxiliary output generated
by the compiler itself. Note that these tables are not released (collapsed) after
exit from a block, as the information gathered may be required to generate a post-
mortem dump. They are also accessed by some orders during program execution,
e.g. by procedure calls and index orders. This makes it unnecessary to copy certain
information into the code (e.g. array-index bounds and data-segment lengths),
thereby contributing to code density.

    0 program testO(output);
    0    const ten = 10; plus = '+';
    0    type row = array [I..ten] of real;
    0         complex = record re,im: real end;
    0    var i, j: integer;
    0        p: boolean;
    0        z: complex; r
    0        matrix: array [-3..+3] of row;
    0        pattern: array [1..5,1..5] of char;
    0
    0 procedure dummy(var i: integer; var z: complex);
    0    var u,v: row;
    0        hl,h2: record c: complex;r: row
    0               end;
    0
    0    function null(x,y:real; z: complex): boolean;

⌨️ 快捷键说明

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