A Practical Approach To Compiler Construction 1st Edition Des Watson (Auth.)

Download as pdf or txt
Download as pdf or txt
You are on page 1of 62

Download the full version of the textbook now at textbookfull.

com

A Practical Approach to Compiler Construction


1st Edition Des Watson (Auth.)

https://textbookfull.com/product/a-practical-
approach-to-compiler-construction-1st-edition-des-
watson-auth/

Explore and download more textbook at https://textbookfull.com


Recommended digital products (PDF, EPUB, MOBI) that
you can download immediately if you are interested.

A Practical Guide to Construction Adjudication 1st Edition


Pickavance

https://textbookfull.com/product/a-practical-guide-to-construction-
adjudication-1st-edition-pickavance/

textbookfull.com

IBM SPSS by example a practical guide to statistical data


analysis Second Edition Service Des Sociétés Secrètes

https://textbookfull.com/product/ibm-spss-by-example-a-practical-
guide-to-statistical-data-analysis-second-edition-service-des-
societes-secretes/
textbookfull.com

A Practical Guide to Construction of Hydropower Facilities


1st Edition Suchintya Kumar Sur

https://textbookfull.com/product/a-practical-guide-to-construction-of-
hydropower-facilities-1st-edition-suchintya-kumar-sur/

textbookfull.com

A Counselor s Guide to the Dissertation Process Where to


Start and How to Finish 1st Edition Flamez

https://textbookfull.com/product/a-counselor-s-guide-to-the-
dissertation-process-where-to-start-and-how-to-finish-1st-edition-
flamez/
textbookfull.com
Introduction to instrumentation and measurements Third
Edition Northrop

https://textbookfull.com/product/introduction-to-instrumentation-and-
measurements-third-edition-northrop/

textbookfull.com

Chatbots And The Domestication Of AI: A Relational


Approach Hendrik Kempt

https://textbookfull.com/product/chatbots-and-the-domestication-of-ai-
a-relational-approach-hendrik-kempt/

textbookfull.com

Oxford Guides to Chaucer the Canterbury Tales 3rd Edition


Cooper

https://textbookfull.com/product/oxford-guides-to-chaucer-the-
canterbury-tales-3rd-edition-cooper/

textbookfull.com

Last Temptation Second Chance Romance 4 1st Edition Nina


Dallas

https://textbookfull.com/product/last-temptation-second-chance-
romance-4-1st-edition-nina-dallas/

textbookfull.com

The Routledge Guidebook to James s Principles of


Psychology 1st Edition David E Leary

https://textbookfull.com/product/the-routledge-guidebook-to-james-s-
principles-of-psychology-1st-edition-david-e-leary/

textbookfull.com
The Construction of Discourse as Verbal Interaction María
De Los Ángeles Gómez Gónzalez (Editor)

https://textbookfull.com/product/the-construction-of-discourse-as-
verbal-interaction-maria-de-los-angeles-gomez-gonzalez-editor/

textbookfull.com
Undergraduate Topics in Computer Science

Des Watson

A Practical
Approach
to Compiler
Construction
Undergraduate Topics in Computer Science
Undergraduate Topics in Computer Science (UTiCS) delivers high-quality
instructional content for undergraduates studying in all areas of computing and
information science. From core foundational and theoretical material to final-year
topics and applications, UTiCS books take a fresh, concise, and modern approach
and are ideal for self-study or for a one- or two-semester course. The texts are all
authored by established experts in their fields, reviewed by an international advisory
board, and contain numerous examples and problems. Many include fully worked
solutions.

More information about this series at http://www.springer.com/series/7592


Des Watson

A Practical Approach
to Compiler Construction

123
Des Watson
Department of Informatics
Sussex University
Brighton, East Sussex
UK

Series editor
Ian Mackie

Advisory Board
Samson Abramsky, University of Oxford, Oxford, UK
Karin Breitman, Pontifical Catholic University of Rio de Janeiro, Rio de Janeiro, Brazil
Chris Hankin, Imperial College London, London, UK
Dexter Kozen, Cornell University, Ithaca, USA
Andrew Pitts, University of Cambridge, Cambridge, UK
Hanne Riis Nielson, Technical University of Denmark, Kongens Lyngby, Denmark
Steven Skiena, Stony Brook University, Stony Brook, USA
Iain Stewart, University of Durham, Durham, UK

ISSN 1863-7310 ISSN 2197-1781 (electronic)


Undergraduate Topics in Computer Science
ISBN 978-3-319-52787-1 ISBN 978-3-319-52789-5 (eBook)
DOI 10.1007/978-3-319-52789-5
Library of Congress Control Number: 2017932112

© Springer International Publishing AG 2017


This work is subject to copyright. All rights are reserved by the Publisher, whether the whole or part
of the material is concerned, specifically the rights of translation, reprinting, reuse of illustrations,
recitation, broadcasting, reproduction on microfilms or in any other physical way, and transmission
or information storage and retrieval, electronic adaptation, computer software, or by similar or dissimilar
methodology now known or hereafter developed.
The use of general descriptive names, registered names, trademarks, service marks, etc. in this
publication does not imply, even in the absence of a specific statement, that such names are exempt from
the relevant protective laws and regulations and therefore free for general use.
The publisher, the authors and the editors are safe to assume that the advice and information in this
book are believed to be true and accurate at the date of publication. Neither the publisher nor the
authors or the editors give a warranty, express or implied, with respect to the material contained herein or
for any errors or omissions that may have been made. The publisher remains neutral with regard to
jurisdictional claims in published maps and institutional affiliations.

Printed on acid-free paper

This Springer imprint is published by Springer Nature


The registered company is Springer International Publishing AG
The registered company address is: Gewerbestrasse 11, 6330 Cham, Switzerland
Preface

The study of programming languages and their implementations is a central theme


of computer science. The design of a compiler—a program translating programs
written in a high-level language into semantically equivalent programs in another
language, typically machine code—is influenced by many aspects of computer
science. The compiler allows us to program in high-level languages, and it provides
a layer of abstraction so that we do not have to worry when programming about the
complex details of the underlying hardware.
The designer of any compiler obviously needs to know the details of both the
source language being translated and the language being generated, usually some
form of machine code for the target machine. For non-trivial languages, the com-
piler is itself a non-trivial program and should really be designed by following a
standard structure. Describing this standard structure is one of the key aims of this
book.
The design of compilers is influenced by the characteristics of formal language
specifications, by automata theory, by parsing algorithms, by processor design, by
data structure and algorithm design, by operating system services, by the target
machine instruction set and other hardware features, by implementation language
characteristics and so on, as well as by the needs of the compilers’ users. Coding a
compiler can be a daunting software task, but the process is greatly simplified by
making use of the approaches, experiences, recommendations and algorithms of
other compiler writers.

Why Study Compiler Design?

Why should compiler design be studied? Why is this subject considered to be an


important component of the education of a computer scientist? After all, only a
small proportion of software engineers are employed on large-scale, traditional
compiler projects. But knowing something about what happens within a compiler
can have many benefits. Understanding the technology and limitations of a

v
vi Preface

compiler is important knowledge for any user of a compiler. Compilers are complex
pieces of code and an awareness of how they work can very helpful. The algorithms
used in a compiler are relevant to many other application areas such as aspects of
text decoding and analysis and the development of command-driven interfaces. The
need for simple domain-specific languages occurs frequently and the knowledge of
compiler design can facilitate their rapid implementation.
Writing a simple compiler is an excellent educational project and enhances skills
in programming language understanding and design, data structure and algorithm
design and a wide range of programming techniques. Understanding how a
high-level language program is translated into a form that can be executed by the
hardware gives a good insight into how a program will behave when it runs, where
the performance bottlenecks will be, the costs of executing individual high-level
language statements and so on. Studying compiler design makes you a better
programmer.

Why Another Book?

Why is there now yet another book on compiler design? Many detailed and
comprehensive textbooks in this field have already been published. This book is a
little different from most of the others. Hopefully, it presents key aspects of the
subject in an accessible way, using a practical approach. The algorithms shown
are all capable of straightforward implementation in almost any programming
language, and the reader is strongly encouraged to read the text and in parallel
produce code for implementations of the compiler modules being described. These
practical examples are concentrated in areas of compiler design that have general
applicability. For example, the algorithms shown for performing lexical and syntax
analysis are not restricted for use in compilers alone. They can be applied to the
analysis required in a wide range of text-based software.
The field of programming language implementation is huge and this book covers
only a small part of it. Just the basic principles, potentially applicable to all
compilers, are explained in a practical way.

What’s in this Book?

This book introduces the topic of compiler construction using many programmed
examples, showing code that could be used in a range of compiler and
compiler-related projects. The code examples are nearly all written in C, a mature
language and still in widespread use. Translating them into another programming
language should not cause any real difficulty. Many existing compiler projects are
written in C, many new compiler projects are being written in C and there are many
compiler construction tools and utilities designed to support compiler
Preface vii

implementations in C. Character handling and dynamic data structure management


are well-handled by C. It is a good language for compiler construction. Therefore, it
may have seemed appropriate to choose the construction of a C compiler as a
central project for this textbook. However, this would not have been sensible
because it is a huge project, and the key algorithms of language analysis and
translation would be overwhelmed by the detail necessary to deal with the
numerous complexities of a “real” programming language, even one regarded as
being simpler than many.
This book is primarily about compiler construction, and it is not specifically
about the use of compiler-related algorithms in other application areas. Hopefully,
though, there is enough information in the analysis chapters to show how these
standard grammar-based techniques can be applied very much more widely.
Although many examples in this book are taken from code that may appear in a
complete C compiler, the emphasis is on the development of a compiler for the DL
language. This is a very simple language developed for the needs of this book from
languages used in a series of practical exercises from various undergraduate and
postgraduate compiler construction courses presented by the author. The syntax of
DL is loosely based on a subset of C, but with many restrictions. In particular, there
is just one data type (the integer), and although functions are supported, their
functionality is rather restricted. Nevertheless, DL is sufficiently powerful to be
usable for real problems. The syntax of DL is presented in the appendix.
The widely-available flex and bison tools are introduced, and their use in
practical implementations is discussed, especially in the context of generating a
compiler for DL. These particular packages provide a good insight into the benefits
offered by the many powerful compiler generation tools now available.
The software examples in this book were developed and tested on systems
running Fedora Linux on an x86-64 architecture. The C compiler used was GCC.
Machine and operating system dependencies are probably inevitable, but any
changes needed to move this code to a different computer or operating system
should be comparatively minor.
The code examples are concentrated on the compiler’s front-end. Code for
intermediate code optimisation, target machine code generation and optimisation
tends to be long, complex and often overwhelmed by target machine detail. Hence,
code examples from the back-end are largely avoided in this book so that no
introduction to or detailed discussion of assembly language programming is
included. Instead, the text presents the basic principles of back-end design from
which code generators for diverse target architectures can be developed. References
are given to sources providing further algorithm examples.
The source code of a complete DL compiler is not presented in this book. The
real reason for this is that there is an underlying assumption that one of the most
important practical exercises of the book is to produce a complete compiler for DL.
A large number of code examples taken from a compiler are included in the text to
illustrate the principles being described so that the reader will not be coding from
scratch.
viii Preface

How Should this Book be Used?

This book can be used to accompany taught courses in programming language


implementation and compiler design, and it can also be used for self-study. There is
an assumption that students using this book will have some programming skills but
not necessarily significant experience of writing large software systems. A working
understanding of basic data structures such as trees is essential. The examples in the
book are coded in C, but a comprehensive knowledge of C is really not required to
understand these examples and the accompanying text. A basic knowledge of
computer hardware is also assumed, including just the rudiments of the principles of
assembly-level programming.
Each chapter ends with a few exercises. They vary a great deal in complexity.
Some involve just a few minutes of thought, whereas others are major programming
projects. Many of the exercises are appropriate for group discussion and some may
form the basis of group projects involving code implementation as well as research.
It is especially important to make the most of the practical aspects of this subject
by coding parts of a compiler as the book is being read. This will help greatly to
alleviate boredom and will hugely help with the process of understanding. For
example, for the newcomer to recursive descent parsing, the power and elegance
of the technique can only be fully appreciated when a working implementation has
been written.
The obvious project work associated with this book is to write a complete
compiler for the DL language. Assuming that a simple target machine is chosen, the
project is of a reasonable size and can fit well into an average size university or
college course. Extensions to such a compiler by including optimisation and reg-
ister allocation can follow in a more advanced course. The project can be taken
even further by developing the DL compiler into a complete C compiler, but the
time required to do this should not be underestimated. Writing a simple compiler
following the steps described in this book is not a huge task. But it is important not
to abandon the standard techniques. I have seen some students getting into major
difficulties with the implementation of their compilers, coded using a “much better
algorithm” of their own devising! The correct approach is reliable and really does
involve a careful and systematic implementation with extensive testing of each
module before it is combined with others.
Although the DL language is used as an example in most of the chapters, this
book is not intended to be a tutorial guide for writing DL compilers. Its aims are
much broader than this—it tries to present the principles of compiler design and the
implementation of certain types of programming language, and where appropriate,
DL-targeted examples are presented. Should the reader want to accept the challenge
of writing a complete DL compiler (and I would certainly recommend this), then the
key practical information about lexical and syntax analysis is easy to find in
Chaps. 3 and 5 and semantic analysis in Chap. 6. There is then some information
about DL-specific issues of code generation in Chap. 8.
Preface ix

Turning the compiler construction project into a group project worked well.
Programming teams can be made responsible for the construction of a complete
compiler. The development can be done entirely by members of the team or it may
be possible for teams to trade with other teams. This is a good test of
well-documented interfaces. Producing a set of good test programs to help verify
that a compiler works is an important part of the set of software modules produced
by each team.
Generating standard-format object code files for real machines in an introductory
compilers course may be trying to go a little too far. Generating assembly code for a
simple processor or for a simple subset of a processor’s features is probably a better
idea. Coding an emulator for a simple target machine is not difficult—just use the
techniques described in this book, of course. Alternatively, there are many virtual
target architecture descriptions with corresponding emulator software freely avail-
able. The MIPS architecture, with the associated SPIM software [1], despite its age,
is still very relevant today and is a good target for code generation. The pleasure of
writing a compiler that produces code that actually runs is considerable!

Acknowledgement This book is loosely based on material presented in several


undergraduate and postgraduate lecture courses at the University of Sussex.
I should like to thank all the students who took these courses and who shared my
enthusiasm for the subject. Over the years, I watched thousands of compilers being
developed and discovered which parts of the process they usually found difficult.
I hope that I have addressed those issues properly in this book.
Thanks also go to my colleagues at the University of Sussex—in particular to all
the staff and students in the Foundations of Software Systems research group who
provided such a supportive and stimulating work environment. Particular thanks go
to Bernhard Reus for all his suggestions and corrections.
I’m really grateful to Ian Mackie, the UTICS series editor, and to Helen
Desmond at Springer for their constant enthusiasm for the book. They always
provided advice and support just when it was needed.
Finally, and most important, I should like to thank Wendy, Helen and Jonathan
for tolerating my disappearing to write and providing unfailing encouragement.

Sussex, UK Des Watson

Reference

1. Larus JR (1990) SPIM S20: a MIPS R2000 simulator. Technical Report 966. University of
Wisconsin-Madison, Madison, WI, Sept 1990
Visit https://textbookfull.com
now to explore a rich
collection of eBooks, textbook
and enjoy exciting offers!
Contents

1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1 High-Level Languages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1.1 Advantages of High-Level Languages . . . . . . . . . . . . . . . . 2
1.1.2 Disadvantages of High-Level Languages . . . . . . . . . . . . . . 3
1.2 High-Level Language Implementation . . . . . . . . . . . . . . . . . . . . . . 5
1.2.1 Compilers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.2.2 Compiler Complexity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.2.3 Interpreters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.3 Why Study Compilers? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.4 Present and Future . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.5 Conclusions and Further Reading . . . . . . . . . . . . . . . . . . . . . . . . . 11
References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2 Compilers and Interpreters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.1 Approaches to Programming Language Implementation . . . . . . . . 13
2.1.1 Compile or Interpret? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.2 Defining a Programming Language . . . . . . . . . . . . . . . . . . . . . . . . 16
2.2.1 BNF and Variants. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.2.2 Semantics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.3 Analysis of Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.3.1 Grammars . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.3.2 Chomsky Hierarchy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.3.3 Parsing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
2.4 Compiler and Interpreter Structure . . . . . . . . . . . . . . . . . . . . . . . . . 28
2.4.1 Lexical Analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
2.4.2 Syntax Analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
2.4.3 Semantic Analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
2.4.4 Machine-Independent Optimisation. . . . . . . . . . . . . . . . . . . 31
2.4.5 Code Generation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
2.4.6 Machine-Dependent Optimisation . . . . . . . . . . . . . . . . . . . . 32

xi
xii Contents

2.4.7 Symbol Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33


2.4.8 Implementation Issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
2.5 Conclusions and Further Reading . . . . . . . . . . . . . . . . . . . . . . . . . 34
References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
3 Lexical Analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
3.1 Lexical Tokens. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
3.1.1 An Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
3.1.2 Choosing the List of Tokens . . . . . . . . . . . . . . . . . . . . . . . 39
3.1.3 Issues with Particular Tokens . . . . . . . . . . . . . . . . . . . . . . . 41
3.1.4 Internal Representation of Tokens . . . . . . . . . . . . . . . . . . . 44
3.2 Direct Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
3.2.1 Planning a Lexical Analyser . . . . . . . . . . . . . . . . . . . . . . . . 46
3.2.2 Recognising Individual Tokens. . . . . . . . . . . . . . . . . . . . . . 47
3.2.3 More General Issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
3.3 Regular Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.3.1 Specifying and Using Regular Expressions . . . . . . . . . . . . 57
3.3.2 Recognising Instances of Regular Expressions . . . . . . . . . . 58
3.3.3 Finite-State Machines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
3.4 Tool-Based Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
3.4.1 Towards a Lexical Analyser for C . . . . . . . . . . . . . . . . . . . 62
3.4.2 Comparison with a Direct Implementation . . . . . . . . . . . . . 70
3.5 Conclusions and Further Reading . . . . . . . . . . . . . . . . . . . . . . . . . 72
References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
4 Approaches to Syntax Analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
4.1 Derivations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
4.1.1 Leftmost and Rightmost Derivations . . . . . . . . . . . . . . . . . 76
4.2 Parsing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
4.2.1 Top–Down Parsing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
4.2.2 Parse Trees and the Leftmost Derivation . . . . . . . . . . . . . . 78
4.2.3 A Top–Down Parsing Algorithm . . . . . . . . . . . . . . . . . . . . 82
4.2.4 Classifying Grammars and Parsers . . . . . . . . . . . . . . . . . . . 86
4.2.5 Bottom-Up Parsing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
4.2.6 Handling Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
4.3 Tree Generation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
4.4 Conclusions and Further Reading . . . . . . . . . . . . . . . . . . . . . . . . . 91
References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
5 Practicalities of Syntax Analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
5.1 Top-Down Parsing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
5.1.1 A Simple Top-Down Parsing Example . . . . . . . . . . . . . . . . 97
5.1.2 Grammar Transformation for Top-Down Parsing . . . . . . . . 100
Contents xiii

5.2 Bottom-Up Parsing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100


5.2.1 Shift-Reduce Parsers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
5.2.2 Bison—A Parser Generator . . . . . . . . . . . . . . . . . . . . . . . . 103
5.3 Tree Generation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
5.4 Syntax Analysis for DL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
5.4.1 A Top-Down Syntax Analyser for DL . . . . . . . . . . . . . . . . 113
5.4.2 A Bottom-Up Syntax Analyser for DL . . . . . . . . . . . . . . . . 124
5.4.3 Top-Down or Bottom-Up? . . . . . . . . . . . . . . . . . . . . . . . . . 131
5.5 Error Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
5.6 Declarations and Symbol Tables . . . . . . . . . . . . . . . . . . . . . . . . . . 134
5.7 What Can Go Wrong? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
5.8 Conclusions and Further Reading . . . . . . . . . . . . . . . . . . . . . . . . . 137
References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
6 Semantic Analysis and Intermediate Code . . . . . . . . . . . . . . . . . . . . . 141
6.1 Types and Type Checking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
6.1.1 Storing Type Information . . . . . . . . . . . . . . . . . . . . . . . . . . 142
6.1.2 Type Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
6.2 Storage Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
6.2.1 Access to Simple Variables . . . . . . . . . . . . . . . . . . . . . . . . 147
6.2.2 Dealing with Scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
6.2.3 Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
6.2.4 Arrays and Other Structures . . . . . . . . . . . . . . . . . . . . . . . . 150
6.3 Syntax-Directed Translation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
6.3.1 Attribute Grammars . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
6.4 Intermediate Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
6.4.1 Linear IRs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
6.4.2 Graph-Based IRs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
6.5 Practical Considerations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
6.5.1 A Three-Address Code IR . . . . . . . . . . . . . . . . . . . . . . . . . 162
6.5.2 Translation to the IR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
6.5.3 An Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
6.6 Conclusions and Further Reading . . . . . . . . . . . . . . . . . . . . . . . . . 173
References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
7 Optimisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
7.1 Approaches to Optimisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178
7.1.1 Design Principles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178
7.2 Local Optimisation and Basic Blocks . . . . . . . . . . . . . . . . . . . . . . 180
7.2.1 Constant Folding and Constant Propagation . . . . . . . . . . . . 181
7.2.2 Common Subexpressions . . . . . . . . . . . . . . . . . . . . . . . . . . 182
7.2.3 Elimination of Redundant Code . . . . . . . . . . . . . . . . . . . . . 186
7.3 Control and Data Flow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187
7.3.1 Non-local Optimisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
xiv Contents

7.3.2 Removing Redundant Variables . . . . . . . . . . . . . . . . . . . . . 190


7.3.3 Loop Optimisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
7.4 Parallelism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
7.4.1 Parallel Execution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
7.4.2 Detecting Opportunities for Parallelism . . . . . . . . . . . . . . . 197
7.4.3 Arrays and Parallelism . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
7.5 Conclusions and Further Reading . . . . . . . . . . . . . . . . . . . . . . . . . 201
References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202
8 Code Generation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
8.1 Target Machines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
8.1.1 Real Machines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206
8.1.2 Virtual Machines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
8.2 Instruction Selection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
8.3 Register Allocation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212
8.3.1 Live Ranges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214
8.3.2 Graph Colouring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
8.3.3 Complications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
8.3.4 Application to DL’s Intermediate Representation . . . . . . . . 219
8.4 Function Call and Stack Management . . . . . . . . . . . . . . . . . . . . . . 219
8.4.1 DL Implementation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
8.4.2 Call and Return Implementation . . . . . . . . . . . . . . . . . . . . . 221
8.5 Optimisation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
8.5.1 Instruction-Level Parallelism . . . . . . . . . . . . . . . . . . . . . . . 223
8.5.2 Other Hardware Features . . . . . . . . . . . . . . . . . . . . . . . . . . 226
8.5.3 Peephole Optimisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228
8.5.4 Superoptimisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229
8.6 Automating Code Generator Construction . . . . . . . . . . . . . . . . . . . 230
8.7 Conclusions and Further Reading . . . . . . . . . . . . . . . . . . . . . . . . . 231
References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
9 Implementation Issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235
9.1 Implementation Strategies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235
9.1.1 Cross-Compilation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
9.1.2 Implementation Languages . . . . . . . . . . . . . . . . . . . . . . . . . 237
9.1.3 Portability . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
9.2 Additional Software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240
9.3 Particular Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242
9.4 The Future . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
9.5 Conclusions and Further Reading . . . . . . . . . . . . . . . . . . . . . . . . . 243
References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245
Appendix A: The DL Language . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
List of Figures

Figure 2.1 A simple view of programming language implementation . . . . 14


Figure 2.2 A trivial language . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
Figure 2.3 BNF for simple arithmetic expressions . . . . . . . . . . . . . . . . . . . 18
Figure 2.4 Syntactic structure of the expression 1 + 2 * 3 . . . . . . . . . . . . 26
Figure 2.5 The analysis/synthesis view of compilation . . . . . . . . . . . . . . . 28
Figure 2.6 Phases of compilation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Figure 3.1 Directed graph representation of ðabjcÞd . . . . . . . . . . . . . . . . 58
Figure 3.2 Transition diagram for the regular expression ðabjcÞ  d . . . . . 59
Figure 4.1 BNF for a trivial arithmetic language . . . . . . . . . . . . . . . . . . . . 75
Figure 4.2 Tree from the derivation of x+y*z . . . . . . . . . . . . . . . . . . . . . 77
Figure 4.3 Two parse trees for x+y+z . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
Figure 5.1 A very simple DL program . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
Figure 5.2 Tree from the program of Fig. 5.1 . . . . . . . . . . . . . . . . . . . . . . 121
Figure 6.1 Structural equivalence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
Figure 6.2 Annotated tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
Figure 6.3 Tree for a  a=ða  a þ b  bÞ . . . . . . . . . . . . . . . . . . . . . . . . . . 159
Figure 6.4 Common subexpression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
Figure 6.5 Basic blocks with control flow . . . . . . . . . . . . . . . . . . . . . . . . . 160
Figure 6.6 Translation of DL to IR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
Figure 6.7 A generalised tree node . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
Figure 7.1 Basic blocks of factorial main program (see appendix) . . . . . . . 181
Figure 7.2 Flow between basic blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
Figure 8.1 Trees representing machine instructions . . . . . . . . . . . . . . . . . . 211
Figure 8.2 Live ranges and register interference graph . . . . . . . . . . . . . . . 216
Figure 8.3 Graph colouring algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
Figure 8.4 Graph colouring algorithm—register allocation . . . . . . . . . . . . 218

xv
Chapter 1
Introduction

The high-level language is the central tool for the development of today’s software.
The techniques used for the implementation of these languages are therefore very
important. This book introduces some of the practicalities of producing implemen-
tations of high-level programming languages on today’s computers. The idea of a
compiler, traditionally translating from the high-level language source program to
machine code for some real hardware processor, is well known but there are other
routes for language implementation. Many programmers regard compilers as being
deeply mysterious pieces of software—black boxes which generate runnable code—
but some insight into the internal workings of this process may help towards their
effective use.
Programming language implementation has been studied for many years and it is
one of the most successful areas of computer science. Today’s compilers can generate
highly optimised code from complex high-level language programs. These compilers
are large and extremely complex pieces of software. Understanding what they do and
how they do it requires some background in programming language theory as well
as processor design together with a knowledge of how best to structure the processes
required to translate from one computer language to another.

1.1 High-Level Languages

Even in the earliest days of electronic computing in the 1940s it was clear that there
was a need for software tools to support the programming process. Programming was
done in machine code, it required considerable skill and was hard work, slow and
error prone. Assembly languages were developed, relieving the programmer from
having to deal with much of the low-level detail, but requiring an assembler, a piece
of software to translate from assembly code to machine code. Giving symbolic names
to instructions, values, storage locations, registers and so on allows the programmer
© Springer International Publishing AG 2017 1
D. Watson, A Practical Approach to Compiler Construction, Undergraduate
Topics in Computer Science, DOI 10.1007/978-3-319-52789-5_1
2 1 Introduction

to concentrate on the coding of the algorithms rather than on the details of the binary
representation required by the hardware and hence to become more productive. The
abstraction provided by the assembly language allows the programmer to ignore the
fine detail required to interact directly with the hardware.
The development of high-level languages gathered speed in the 1950s and beyond.
In parallel there was a need for compilers and other tools for the implementation
of these languages. The importance of formal language specifications was recog-
nised and the correspondence between particular grammar types and straightforward
implementation was understood. The extensive use of high-level languages prompted
the rapid development of a wide range of new languages, some designed for particular
application areas such as COBOL for business applications [1] and FORTRAN for
numerical computation [2]. Others such as PL/I (then called NPL) [3] tried to be very
much more general-purpose. Large teams developed compilers for these languages
in an environment where target machine architectures were changing fast too.

1.1.1 Advantages of High-Level Languages

The difficulties of programming in low-level languages are easy to see and the need
for more user-friendly languages is obvious. A programming notation much closer
to the problem specification is required. Higher level abstractions are needed so that
the programmer can concentrate more on the problem rather than the details of the
implementation of the solution.
High-level languages can offer such abstraction. They offer many potential advan-
tages over low-level languages including:

• Problem solving is significantly faster. Moving from the problem specification to


code is simpler using a high-level language. Debugging high-level language code
is much easier. Some high-level languages are suited to rapid prototyping, making
it particularly easy to try out new ideas and add debugging code.
• High-level language programs are generally easier to read, understand and hence
maintain. Maintenance of code is now a huge industry where programmers are
modifying code unlikely to have been written by themselves. High-level language
programs can be made, at least to some extent, self-documenting, reducing the
need for profuse comments and separate documentation. The reader of the code is
not overwhelmed by the detail necessary in low-level language programs.
• High-level languages are easier to learn.
• High-level language programs can be structured more easily to reflect the structure
of the original problem. Most current high-level languages support a wide range
of program and data structuring features such as object orientation, support for
asynchronous processes and parallelism.
• High-level languages can offer software portability. This demands some degree of
language standardisation. Most high-level languages are now fairly tightly defined
1.1 High-Level Languages 3

so that, for example, moving a Java program from one machine to another with
different architectures and operating systems should be an easy task.
• Compile-time checking can remove many bugs at an early stage, before the pro-
gram actually runs. Checking variable declarations, type checking, ensuring that
variables are properly initialised, checking for compatibility in function arguments
and so on are often supported by high-level languages. Furthermore, the compiler
can insert runtime code such as array bound checking. The small additional runtime
cost may be a small price to pay for early removal of errors.

1.1.2 Disadvantages of High-Level Languages

Despite these significant advantages, there may be circumstances where the use of a
low-level language (typically an assembly language) may be more appropriate. We
can identify possible advantages of the low-level language approach.

• The program may need to perform some low-level, hardware-specific operations


which do not correspond to a high-level language feature. For example, the hard-
ware may store device status information in a particular storage location—in most
high-level languages there is no way to express direct machine addressing. There
may be a need to perform low-level i/o, or make use of a specific machine instruc-
tion, again probably difficult to express in a high-level language.
• The use of low-level languages is often justified on the grounds of efficiency in
terms of execution speed or runtime storage requirements. This is an important
issue and is discussed later in this section.

These disadvantages of high-level languages look potentially serious. They need


further consideration.

1.1.2.1 Access to the Hardware

A program running on a computer system needs to have access to its environment.


It may input data from the user, it may need to output results, create a file, find the
time of day and so on. These tasks are hardware and operating system specific and
to achieve some portability in coding the high-level language program performing
these actions, the low-level details have to be hidden. This is conventionally done by
providing the programmer with a library acting as an interface between the program
and the operating system and/or hardware. So if the program wants to write to a
file, it makes a call to a library routine and the library code makes the appropriate
operating system calls and performs the requested action.
To address the stated advantage of low-level languages mentioned above there is
nothing to stop the construction of operating system and machine-specific libraries
to perform the special-purpose tasks such as providing access to a particular storage
4 1 Introduction

location or executing a particular machine instruction. There may be machine-specific


problems concerned with the mechanism used to call and return from this library
code with, for example, the use of registers, or with the execution time cost of the
call and return, but such difficulties can usually be overcome.
A few programming languages provide an alternative solution by supporting inline
assembly code. This code is output unchanged by the compiler, providing the high-
level language program direct access to the hardware. This is a messy solution,
fraught with danger, and reliable means have to be set up to allow data to be passed
into and returned from this code. Such facilities are rarely seen today.

1.1.2.2 Efficiency

There are many programming applications where efficiency is a primary concern.


These could be large-scale computations requiring days or weeks of processor time
or even really short computations with severe real-time constraints. Efficiency is
usually concerned with the minimisation of computation time, but other constraints
such as memory usage or power consumption could be more important.
In the early development of language implementations, the issue of efficiency
strongly influenced the design of compilers. The key disadvantage of high-level
languages was seen as being one of poor efficiency. It was assumed that machine-
generated code could never be as efficient as hand-written code. Despite some
remarkable optimisations performed by some of the early compilers (particularly
for FORTRAN), this remained largely true for many years. But as compiler tech-
nology steadily improved, as processors became faster and as their architectures
became more suited to running compiler-generated code from high-level language
programs, the efficiency argument became much less significant. Today, compiler-
generated code for a wide range of programming languages and target machines is
likely to be just as efficient, if not more so, than hand-written code.
Does this imply that justifying the use of low-level languages on the grounds
of producing efficient code is now wrong? The reality is that there may be some
circumstances where coding in machine or assembly code, very carefully, by hand,
will lead to better results. This is not really feasible where the amount of code is
large, particularly where the programmer loses sight of the large-scale algorithmic
issues while concentrating on the small-scale detail. But it may be a feasible approach
where, for example, a small function needs to run particularly quickly and the skills
of a competent low-level programmer with a good knowledge of the target machine
are available. Mixing high-level language programming with low-level language
programming is perfectly reasonable in this way. But if the amount of code to be
optimised is very small, other automated methods may be available (for example [4]).
When developing software, a valuable rule to remember is that there is no need
to optimise if the code is already fast enough. Modern processors are fast and a huge
amount can be achieved during the time taken for a human to react to the computer’s
output. However, this does not imply that compilers need never concern themselves
1.1 High-Level Languages 5

with code optimisation—there will always be some applications genuinely needing


the best out of the hardware.
The case for using high-level languages for almost all applications is now very
strong. In order to run programs written in high-level languages, we need to consider
how they can be implemented.

1.2 High-Level Language Implementation

A simplistic but not inaccurate view of the language implementation process suggests
that some sort of translator program is required (a compiler) to transform the high-
level language program into a semantically equivalent machine code program that
can run on the target machine. Other software, such as libraries, will probably also
be required. As the complexity of the source language increases as the language
becomes “higher and higher-level”, closer to human expression, one would expect
the complexity of the translator to increase too.
Many programming languages have been and are implemented in this way. And
this book concentrates on this implementation route. But other routes are possible,
and it may be the characteristics of the high-level language that forces different
approaches. For example, the traditional way of implementing Java makes use of
the Java Virtual Machine (JVM) [5], where the compiler translates from Java source
code into JVM code and a separate program (an interpreter) reads these virtual
machine instructions, emulating the actions of the virtual machine, effectively run-
ning the Java program. This seemingly contrary implementation method does have
significant benefits. In particular it supports Java’s feature of dynamic class loading.
Without such an architecture-neutral virtual machine code, implementing dynamic
class loading would be very much more difficult. More generally, it allows the support
of reflection, where a Java program can examine or modify at runtime the internal
properties of the executing program.
Interpreted approaches are very appropriate for the implementation of some pro-
gramming languages. Compilation overheads are reduced at the cost of longer run-
times. The programming language implementation field is full of tradeoffs. These
issues of compilers versus interpreters are investigated further in Chap. 2.
To make effective use of a high-level language, it is essential to know something
about its implementation. In some demanding application areas such as embedded
systems where a computer system with a fixed function is controlling some elec-
tronic or mechanical device, there may be severe demands placed on the embedded
controller and the executing code. There may be real-time constraints (for example,
when controlling the ignition timing in a car engine where a predefined set of opera-
tions has to complete in the duration of a spark), memory constraints (can the whole
program fit in the 64 k bytes available on the cheap version of the microcontroller
chip?) or power consumption constraints (how often do I have to charge the batter-
ies in my mobile phone?). These constraints make demands on the performance of
the hardware but also on the way in which the high-level language implementing
Visit https://textbookfull.com
now to explore a rich
collection of eBooks, textbook
and enjoy exciting offers!
6 1 Introduction

the system’s functionality is actually implemented. The designers need to have an


in-depth knowledge of the implementation to be able to deal with these issues.

1.2.1 Compilers

The compiler is a program translating from a source language to a target language,


implemented in some implementation language. As we have seen, the traditional view
of a compiler is to take some high-level language as input and generate machine code
for some target machine. Choice of implementation language is an interesting issue
and we will see later in Chap. 9 why the choice of this language may be particularly
important.
The field of compilation is not restricted to the generation of low-level language
code. Compiler technology can be developed to translate from one high-level lan-
guage to another. For example, some of the early C++ compilers generated C code
rather than target machine code. Existing C compilers were available to perform the
final step.
The complexity of a compiler is not only influenced by the complexities of the
source and target languages, but also by the requirement for optimised target code.
There is a real danger in compiler development of being overwhelmed by the com-
plexities and the details of the task. A well-structured approach to compiler devel-
opment is essential.

1.2.2 Compiler Complexity

The tools and processes of programming language implementation cannot be consid-


ered in isolation. Collaboration between the compiler writer, the language designer
and the hardware architect is vital. The needs of the end-users must be incorporated
too. Compilers have responded to the trend towards increased high-level language
complexity and the desire for aggressive optimisation by becoming significantly more
complex themselves. In the early days of compilers the key concern was the gener-
ation of good code, rivalling that of hand coders, for machines with very irregular
architectures. Machine architectures gradually became more regular, hence mak-
ing it easier for the compiler writer. Subsequent changes (from the 1980s) towards
the much simpler instruction sets of the reduced instruction set computers (RISC)
helped simplify the generation of good code. Attention was also being focused on
the design of the high-level languages themselves and the support for structures and
methodologies to help the programmers directly. Today, the pressures caused by new
languages and other tools to support the software development process are still there
and also the rapid move towards distributed computing has placed great demands on
program analysis and code generation. Parallelism, in its various forms, offers higher
performance processing but at a cost of increased implementation complexity.
1.2 High-Level Language Implementation 7

The language implementation does not stop at the compiler. The support of col-
lections of library routines is always required, providing the environment in which
code generated by the compiler can run. Other tools such as debuggers, linkers, doc-
umentation aids and interactive development environments are needed too. This is
no easy task.
Dealing with this complexity requires a strict approach to design in the structuring
of the compiler construction project. Traditional techniques of software engineering
are well applied in compiler projects, ensuring appropriate modularisation, testing,
interface design and so on. Extensive stage-by-stage testing is vital for a compiler.
A compiler may produce highly optimised code, but if that code produces the wrong
answers when it runs, the compiler is not of much use. To ease the task of producing
a programming language implementation, many software tools have been developed
to help generate parts of a compiler or interpreter automatically. For example, lexi-
cal analysers and syntax analysers (two early stages of the compilation process) are
often built with the help of tools taking the formal specification of the syntax of the
programming language as input and generating code to be incorporated in the com-
piler as output. The modularisation of compilers has also helped to reduce workload.
For example, many compilers have been built using a target machine independent
front-end and a source language-independent back-end using a standard intermediate
representation as the interface between them. Then front-ends and back-ends can be
mixed and matched to produce a variety of complete compilers. Compiler projects
rarely start from scratch today.
Fortunately, in order to learn about the principles of language implementation,
compiler construction can be greatly simplified. If we start off with a simple pro-
gramming language and generate code for a simple, maybe virtual, machine, not
worrying too much about high-quality code, then the compiler construction project
should not be too painful or protracted.

1.2.3 Interpreters

Running a high-level language program using a compiler is a two-stage process. In the


first stage, the source program is translated into target machine code and in the second
stage, the hardware executes or a virtual machine interprets this code to produce
results. Another popular approach to language implementation generates no target
code. Instead, an interpreter reads the source program and “executes” it directly.
So if the interpreter encounters the source statement a = b + 1, it analyses the
source characters to determine that the input is an assignment statement, it extracts
from its own data structures the value of b, adds one to this value and stores the result
in its own record of a.
This process of source-level interpretation sounds attractive because there is no
need for the potentially complex implementation of code generation. But there are
practical problems. The first problem concerns performance. If a source statement
is executed repeatedly it is analysed each time, before each execution. The cost of
8 1 Introduction

possibly multiple statement analysis followed by the interpreter emulating the action
of the statement will be many times greater than the cost of executing a few machine
instructions obtained from a compilation of a = b + 1. However this cost can
be reduced fairly easily by only doing the analysis of the program once, translating
it into an intermediate form that is subsequently interpreted. Many languages have
been implemented in this way, using an interpreted intermediate form, despite the
overhead of interpretation.
The second problem concerns the need for the presence of an interpreter at runtime.
When the program is “executing” it is located in the memory of the target system in
source or in a post-analysis intermediate form, together with the interpreter program.
It is likely that the total memory footprint is much larger than that of equivalent
compiled code. For small, embedded systems with very limited memory this may be
a decisive disadvantage.
All programming language implementations are in some sense interpreted. With
source code interpretation, the interpreter is complex because it has to analyse the
source language statements and then emulate their execution. With intermediate code
interpretation, the interpreter is simpler because the source code analysis has been
done in advance. With the traditional compiled approach with the generation of
target machine code, the interpretation is done entirely by the target hardware, there
is no software interpretation and hence no overhead. Looking at these three levels of
interpretation in greater detail, one can easily identify tradeoffs:

Source-level interpretation—interpreter complexity is high, the runtime efficiency is


low (repeated analysis and emulation of the source code statements), the initial
compilation cost is zero because there is no separate compiler and hence the delay
in starting the execution of the program is also zero.
Intermediate code interpretation—interpreter complexity is lower, the runtime effi-
ciency is improved (the analysis and emulation of the intermediate code statements
is comparatively simple), there is an initial compilation cost and hence there is a
delay in starting the program.
Target code interpretation—full compilation—there is no need for interpreter soft-
ware so interpreter complexity is zero, the runtime efficiency is high (the inter-
pretation of the code is done directly by the hardware), there is a potentially large
initial compilation cost and hence there may be a significant delay in starting the
program.

The different memory requirements of the three approaches are somewhat harder
to quantify and depend on implementation details. In the source-level interpretation
case, a simplistic implementation would require both the text of the source code and
the (complex) interpreter to be in main memory. The intermediate code interpretation
case would require the intermediate code version of the program and the (simpler)
interpreter to be in main memory. And in the full compilation case, just the compiled
target code would need to be in main memory. This, of course, takes no account of the
memory requirements of the running program—space for variables, data structures,
buffers, library code, etc.
1.2 High-Level Language Implementation 9

There are other tradeoffs. For example, when the source code is modified, there is
no additional compilation overhead in the source-level interpretation case, whereas in
the full compilation case, it is usual for the entire program or module to be recompiled.
In the intermediate code interpretation case, it may be possible to just recompile the
source statements that have changed, avoiding a full recompilation to intermediate
code.
Finally, it should be emphasised that this issue of lower efficiency of interpreted
implementations is rarely a reason to dismiss the use of an interpreter. The interpreting
overhead in time and space may well be irrelevant, particularly in larger computer
systems, and the benefits offered may well overwhelm any efficiency issues.

1.3 Why Study Compilers?

It is important to ask why the topic of compiler construction is taught to computer


science students. After all, the number of people who actually spend their time
writing compilers is small. Although the need for compilers is clear, there is not
really a raging demand for the construction of new compilers for general-purpose
programming languages.
One of the key motivations for studying this technology is that compiler-related
algorithms have relevance to application areas outside the compiler field. For exam-
ple, transforming data from one syntactic form into another can be approached by
considering the grammar of the structure of the source data and using traditional
parsing techniques to read this data and then output it in the form of the new gram-
mar. Furthermore, it may be appropriate to develop a simple language to act as a user
interface to a program. The simplicity and elegance of some parsing algorithms and
basing the parsing on a formally specified grammar helps produce uncomplicated
and reliable software tools.
Studying compiler construction offers the computer science student many insights.
It gives a practical application area for many fundamental data structures and algo-
rithms, it allows the construction of a large-scale and inherently modular piece of
software, ideally suited for construction by a team of programmers. It gives an insight
into programming languages, helping to show why some programming languages
are the way they are, making it easier to learn new languages. Indeed, one of the best
ways of learning a programming language is to write a compiler for that language,
preferably writing it in its own language. Writing a compiler also gives some insight
into the design of target machines, both real and virtual.
There is still a great deal of work to be done in developing compilers. As new
programming languages are designed, new compilers are required, and new pro-
gramming paradigms may need novel approaches to compilation. As new hardware
architectures are developed, there is a need for new compilation and code generation
strategies to make effective use of the machine’s features.
Although there is a steady demand for new compilers and related software, there
is also a real need for the development of new methodologies for the construction
10 1 Introduction

of high-quality compilers generating efficient code. Implementing code to analyse


the high-level language program is not likely to be a major challenge. The area has
been well researched and there are good algorithms and software tools to help. But
the software needed to generate target code, particularly high-quality code, is much
harder to design and write. There are few standard approaches for this part of the
compiler. And this is where there is an enormous amount of work still to be done.
For example, generating code to make the best use of parallel architectures is hard,
and we are a long way from a general, practical solution.
Is there really a need for heavily optimised target code? Surely, today’s processors
are fast enough and are associated with sufficiently large memories? This may be
true for some applications, but there are many computations where there are, for
example, essential time or space constraints. These are seen particularly in embedded
applications where processor power or memory sizes may be constrained because of
cost or where there are severe real-time constraints. There will always be a need to
get the most from the combination of hardware and software. The compiler specialist
still has a great deal of work to do.

1.4 Present and Future

Today’s compilers and language tools can deal with complex (both syntactically and
semantically) programming languages, generating code for a huge range of computer
architectures, both real and virtual. The quality of generated code from many of
today’s compilers is astonishingly good, often far better than that generated by a
competent assembly/machine code programmer. The compiler can cope well with
the complex interacting features of computer architectures. But there are practical
limits. For example, the generation of truly optimal code (optimising for speed, size,
power consumption, etc.) may in practice be at best time consuming or more likely
impossible. Where we need to make the best use of parallel architectures, today’s
compilers can usually make a good attempt, but not universally. There are many
unsolved optimisation-related problems. Also, surely there must be better processor
architectures for today’s and tomorrow’s programming languages?
Compilers are not just about generating target code from high-level language
programs. Programmers need software tools, probably built on compiler technology,
to support the generation of high-quality and reliable software. Such tools have
been available for many years to perform very specific tasks. For example, consider
the lint tool [6] to highlight potential trouble spots in C programs. Although huge
advances have been made, much more is required and this work clearly interacts with
programming language design as well as with diverse areas of software engineering.
Random documents with unrelated
content Scribd suggests to you:
itseni ikkunasta eteishuoneen ulkonevalle katolle. Sekuntia
myöhemmin sain pihallaolijain huomion kiintymään itseeni
tipahtamalla maahan keskelle rähäkkää; hätäytynyt Castelroux, joka
luuli minun aikovan karata, seurasi perässäni samaa harvinaista tietä
myöten, huutaen täyttä kurkkua:

»Herra de Lesperon! Hei! Herra de Lesperon! Muistakaa sananne,


herra de
Lesperon!»

Parempaa tapaa Marsacin raivon lauhduttamiseksi ei olisi voitu


keksiä; mikään ei olisi sen paremmin voinut tehdä häntä
taipuvaiseksi kuuntelemaan sanottavaani, sillä oli aivan ilmeistä, että
Castelrouxin sanat olivat tarkoitetut minulle ja että hän käytti juuri
minusta nimeä Lesperon. Hetkeäkään vitkastelematta olin Marsacin
edessä. Mutta ennenkuin ehdin virkkaa mitään, loi hän minuun
tuikean, epäluuloisen silmäyksen ja kysyi:

»Mitä hittoa tämä merkitsee?»

»Se merkitsee, monsieur, että Ranskassa on useampia kuin yksi


Lesperon. Minä olen se Lesperon, joka oli Lavédanissa. Jos epäilette
sanojani, niin kysykää tältä herrasmieheltä, joka pidätti minut siellä
viime yönä! Kysykää häneltä myöskin, miksi olemme pysähtyneet
täällä! Pyytäkää, jos haluatte, häntä näyttämään Lavédaniin
jättämänne kirje, jossa ehdotitte kohtausta täällä tänään
aamupäivällä ja jonka minä sain!»

Epäilyksen ilme haihtui Marsacin kasvoilta, ja hänen silmänsä


menivät levälleen hämmästyksestä, kun hän kuunteli ihmeellistä
todisteluani.
Ennenkuin Marsac kerkisi vastaamaan, riensi Castelroux luokseni
ja puhkesi nauraen puhumaan:

»Pyydän tuhannesti anteeksi! Pässikin olisi saattanut arvata, mikä


teidät niin nopeasti kiidätti ikkunasta, ja vain pässi olisi saattanut
epäillä teidän yrittävän karata. Se oli arvotonta minun puoleltani,
herra de Lesperon.»

Käännyin hänen puoleensa toisten yhä töllistellessä suu auki ja


vein hänet sivulle.

»Herra kapteeni, saanko vielä vaivata teidän ylevämielisyyttänne


anomalla, että sallisitte minun viedä nämä riitaveljet huoneeseemme
ja jättäisitte meidät sinne kolmisin puoleksi tunniksi?»

Avonaisuus oli paras liittolaiseni järjestäessäni asioita Castelrouxin


kanssa — avonaisuus ja hänen vastenmielisyytensä sitä tehtävää
kohtaan, joka hänelle oli annettu. Marsac ja Lesperon taaskin olivat
perin innokkaita kuulemaan salaperäisen sekaannuksen selitystä, ja
kun minä — saatuani Castelrouxin suostumuksen — kutsuin heitä
huoneeseeni, olivat he heti valmiit tulemaan.

Koska herra de Lesperon ilmeisesti ei tuntenut minua, ei minulla


ollut mitään syytä ilmaista heille, ken olin, vaan päinvastoin minulla
oli hyvät syyt pitää se salassa. Heidän istuuduttuaan kävin heti
käsiksi asian ytimeen ilman minkäänlaisia valmistavia puheita.

»Kaksi viikkoa takaperin, hyvät herrat», aloin, »ajoi joukko


rakuunoita minut pakoon Garonnen poikki. Olin haavoittunut
olkapäähän ja hyvin näännyksissä; kolkutin Lavédanin portille,
pyytäen suojaa. Suojaa minulle annettiin, ja kun ilmoitin olevani
herra de Lesperon, kohdeltiin minua sitäkin sydämellisemmin, koska
eräs herra de Marsac, joka oli varakreivi de Lavédanin ystävä ja
Orleansin tuhoutuneen asian kannattaja, oli sattunut usein
puhumaan herra de Lavédanille eräästä herra de Lesperonista, oikein
hyvästä ystävästään. Epäilemättä te, hyvät herrat, tuomitsette minua
siitä, etten selvittänyt varakreiville hänen erehdystään. Mutta minulla
oli syyni, joita te toivoakseni ette vaadi minua ilmaisemaan, sillä
minun olisi vaikea puhua niistä teille totta.»

»Mutta onko teidän nimenne Lesperon?» huudahti Lesperon.

»Se, monsieur, on vähäarvoinen seikka. Olkoonpa nimeni Lesperon


tai ei, joka tapauksessa tunnustan menetelleeni kavalasti varakreiviä
ja hänen perhettään kohtaan, koska varmasti en ole se Lesperon,
jona esiinnyin. Mutta jos omaksuinkin teidän henkilöllisyytenne,
omaksuin myös vastuunalaisuutenne, ja sen vuoksi voitte te
luullakseni jossakin määrin antaa sydämessänne minulle anteeksi.
René de Lesperonina, Lesperonista, Gascognesta, vangittiin minut
viime yönä Lavédanissa ja kuten huomannette, viedään minua
parhaillaan Toulouseen vastaamaan hänen valtiopetossyytöksestään.
En ole empinyt; en ole vastoinkäymisen hetkellä hylännyt sitä nimeä,
josta oli minulle apua tarpeen hetkellä. Otan vastaan pahan, jos
hyvänkin, ja vakuutan teille, hyvät herrat, että edellinen on oikein
tuntuvasti suurempi.»

»Mutta niin ei saa käydä!» kiivasteli Lesperon, nousten seisomaan.


»En tiedä, mihin tarkoitukseen lienette nimeäni käyttänyt, mutta
minulla ei ole mitään syytä uskoa teidän tuottaneen sille häpeää, ja
siksi — »

»Kiitän teitä, monsieur, mutta —»


»Ja siksi en voi suostua siihen, että te menette Toulouseen minun
sijastani. Missä on se upseeri, jonka vanki olette? Kutsukaa hänet
tänne, olkaa niin hyvä, ja pankaamme tämä asia oikealle tolalle!»

»Puhutte hyvin ylevästi», vastasin rauhallisesti. »Mutta minun


niskoillani on riittävästi rikoksia, ja jos minulle osuisikin pahin
mahdollisuus, sovitan niin ollen vain yhdellä kertaa kahden henkilön
erehdykset. Asiani ei ole läheskään toivoton. Olen aivan varma siitä,
että asioiden ollessa nykyisellä kannallaan minä voin paljastamalla
oikealla hetkellä pelini, ilmoittamalla sopivana aikana, kuka olen,
pelastaa niskani pyövelin kirveeltä, jos niin haluan.»

»Jos niin haluatte?» huudahtivat he molemmat, ja heidän


katseensa saivat kysyvän ilmeen.

»Olkoon se sillään», vastasin, »se ei tällä kertaa liikuta meitä.


Mutta ymmärtänette, että minun turvallisuuteni tähden on hyvin
tärkeätä, että te poistutte rauhallisesti Ranskasta ja jätätte jälkeenne
sen luulon, että olette kuollut — mikä luulo pian leviää, sitten kun
minä olen lakannut esiintymästä teinä. Käsitättekö minua?»

»Hämärästi, monsieur, ja kenties olette oikeassa. Mitä arvelet sinä,


Stanislas?»

»Mitäkö arvelen?» huudahti tulinen Marsac. »Painun maan alle


häpeästä,
René-parkani, sentähden että olen tuominnut sinua niin väärin.»

Hän olisi puhunut enemmän samaan suuntaan, mutta Lesperon


keskeytti hänet, kehoittaen häntä pysymään käsillä olevassa asiassa.
Marsac oli matkalla Espanjaan. Hänen sisarensa, hän kertoi, odotti
häntä Carcassonnessa. Lesperonin olisi heti lähdettävä hänen
mukaansa, ja neljässäkymmenessäkahdeksassa tunnissa he olisivat
päässeet pois kuninkaan vihan ulottuvilta.

»Tahtoisin pyytää teiltä erästä palvelusta, herra de Marsac»,


virkoin, nousten seisomaan, sillä asiamme oli lopussa. »Jos teillä on
tilaisuutta lähettää tietoja neiti de Lavédanille, toivoisin teidän
ilmoittavan hänelle, että minä en — en ole se Lesperon, joka on
kihloissa sisarenne kanssa.»

»Toimitan siitä hänelle tiedon, monsieur», vastasi hän empimättä.


Mutta sitten tuli äkkiä hänen silmiinsä ymmärtämyksen ja rajattoman
säälin ilme. »Hyvä jumala! Ettekö — ettekö ollenkaan aavista, miksi
jouduitte kiinni?»

»Koska minun luultiin olleen mukana äskeisessä kapinassa.»

»Niin, kyllä. Mutta kuka ilmaisi olinpaikkanne? Kuka kertoi


sinetinvartijalle, mistä teidät löydetään?»

»Oh, sitäkö?» vastasin keveästi. »Niin, siitä olen ollut koko ajan
varma. Ilmiantaja oli St. Eustache houkkio. Piiskasin häntä —»

Pysähdyin äkkiä. Marsacin tummien kasvojen ilme, hänen


katseensa, sai minut aavistamaan lausumattoman totuuden.

»Jumalan äiti!» huudahdin. »Tarkoitatteko, että se oli neiti de


Lavédan?»

Hän taivutti päätään äänettömänä.


Hyvä jumala! Mikä isku se olikaan. Se teki minut sairaaksi tuskasta
— niin, ja jonkunlaisesta raivosta — ei häntä kohtaan, ei, ei häntä,
vaan kohtaloa kohtaan, joka antoi sellaista tapahtua.

Hillitsin itseni heidän vielä katsellessaan minua.

Heidän poistuttuaan palasin pöydän ääreen, istuuduin, kiersin


käteni pääni ympärille ja nojasin pöytään katkerimman tuskan
vallassa, mitä keveän onnellisen elämäni aikana olin tuntenut.

Sitten muuttui epätoivoni rauhaksi, ensin hitaasti, sitten yhä


nopeammin.

Tajusin, kuinka julma oli sen kolahduksen täytynyt olla, joka oli
ajanut hänet tähän. Mutta hän oli rakastanut minua, niin, hän rakasti
minua vieläkin, vaikkakin hän luuli minua vihaavansa ja vaikka hän
oli toiminut, ikäänkuin hän olisi vihannut.

Se ajatus virkisti minua kuin viini. Enää en ollut turtunut — en


välinpitämätön siitä, elinkö vai kuolinko. Minun täytyi elää. Minun
täytyi todistaa sinetinvartijalle ja toulouselaisille tuomareille, kuka
olin. Totisesti, olinko koskaan empinyt? Uhkean Bardelysin täytyi
virota uudelleen henkiin, ja sitten — Mitä sitten?

Yhtä äkkiä kuin olin riemastunut, lamaannuin jälleen. Jos hän nyt
oli loukkaantunut siitä, että hän luuli minun leikittelevän hänen
tunteillaan, niin eikö sama tunne valtaisi hänet taaskin, kun hän saisi
tietää totuuden?

Niin, sotku oli todella surkea. Mutta minä rohkaisin mieltäni. Vetoni
oli maksettava, ennenkuin taas menisin hänen luokseen, vaikka
jäisinkin todella köyhäksi. Nyt kiitin Jumalaa siitä, ettei hän saisi sitä
tietää, ennenkuin itse palaisin kertomaan siitä hänelle.
XI

KUNINKAAN KÄSKYNHALTIJA

En tavannut uudelleen Marsacia enkä Lesperonia, ennenkuin


lähdimme jälleen matkalle.

Keveällä mielellä en kuitenkaan ollut, sillä Castelroux oli kertonut


minulle, että valtiopetoksesta syytettyjen juttuja käsiteltiin hyvin
summittaisesti, ja se teki minut jonkun verran levottomaksi.

Tämä levottomuus sai minut puhelemaan vangitsijani kanssa


näistä tuomioistuimista, ja koetin saada häneltä tietää, keitä oli
tuomareina. Hän kertoi, että säännöllisen oikeusistuimen lisäksi oli
hänen majesteettinsa lähettänyt Toulouseen käskynhaltijan, jota
odotettiin saapuvaksi sinne joka hetki.

»Tiedättekö tämän kuninkaallisen käskynhaltijan nimen?»


tiedustin.

»Hän on eräs kreivi de Chatellerault, joka kuuluu olevan hänen


majesteettinsa erikoinen suosikki.»

»Chatellerault!» pääsi minulta riemuisan ihmettelevä huudahdus.


»Tunnetteko hänet?»

»Erinomaisesti!» Purskahdin nauramaan. »Olemme hyvin läheisiä


tuttavia.»

»No sitten, monsieur, toivotan teille tämän herrasmiehen


ystävyyttä, ja auttakoon se teidät pois pulasta. Vaikka —»
Luonteeltaan säälivänä miehenä hän keskeytti äkkiä lauseensa.
Mutta minä nauroin keveästi.

»Todellakin, paras kapteeni, luulen, että se tekee sen; vaikka tässä


maailmassa ystävyys on sellainen seikka, jota onnettomat eivät
paljoakaan saa kokea.»

Mutta iloni oli liian aikainen, kuten saatte kuulla.

Ratsastimme reippaasti edelleen; tiemme kulki pitkin Garonnen


hedelmällisiä rantoja, jotka nyt olivat keltaisia kahisevasta viljasta.
Illansuussa pysähdyimme viimeisen kerran Fenouilletissa, josta parin
tunnin ratsastus veisi meidät Toulouseen.

Postitalolla saavutimme eräät vaunut, jotka nähtävästi olivat


pysähtyneet vaihtamaan hevosia, mutta minä tuskin vilkaisinkaan
niihin laskeutuessamme satulasta.

Sillä aikaa kun Castelroux meni tilaamaan levänneitä hevosia,


astuin minä vierassaliin ja seisoin siellä jonkun aikaa, puhellen
isännän kanssa ruuista. Kun lopuksi olin päättänyt, että meille riittäisi
kylmä pasteija ja pullo armagnacia, aloin katsella ympärilleni
nähdäkseni, keitä huoneessa oli. Eräässä huoneen kaukaisessa
nurkassa oleva ryhmä kiinnitti äkkiä huomiotani siinä määrin, etten
kuullut Castelrouxin ääntä, joka juuri oli palannut ja seisoi nyt
vieressäni. Tämän ryhmän keskellä oli itse kreivi de Chatellerault,
tanakkatekoinen, synkännäköinen mies, puettuna hautajaismaisen
juhlallisesti, kuten hänen tapansa oli.

Hämmästykseni johtui pikemminkin siitä, että hänen ympärillään


olevien puolentusinan herrasmiehen joukossa näin — ja ilmeisesti
hänen seurueeseensa kuuluvana — chevalier de St. Eustachen.
Nähtävästi hän oli hyvin läheisissä suhteissa kreivin kanssa, sillä kun
nostin katseeni, näin hänen parhaillaan kumartuneen tutunomaisesti
kuiskaamaan Chatelleraultin korvaan.

Heidän katseensa — jopa koko seurueen katseet — olivat


suunnatut minuun. Kenties ei ollut kummastuttavaa, että
Chatellerault katseli minua niin omituisesti, sillä olihan
todennäköistä, että hän oli kuullut minun kuolleen. Lisäksi se seikka,
ettei minulla ollut miekkaa ja että vierelläni seisoi kuninkaan upseeri,
osoitti selvästi, missä asemassa olin; niinpä Chatelleraultilla
todellakin oli syytä tuijottaa, nähdessään minut niin selvästi vankina.

Juuri silmäillessäni häntä, hän näkyi hätkähtävän jostakin, mitä St.


Eustache hänelle sanoi, ja hänen ilmeensä muuttui kummallisesti.

»Tuo mies», kuiskasi Castelroux korvaani, »on kuninkaan


käskynhaltija.»

Enkö minä sitä tiennyt? En jäänyt vastaamaan hänelle, vaan


astelin lattian poikki ja ojensin käteni — pöydän yli —
Chatelleraultille.

»Hyvä kreivi», huudahdin, »olettepa totisesti tervetullut!»


Olisin puhunut enemmänkin, mutta hänen olemuksessaan oli
jotakin, mikä sai minut vaikenemaan. Hän oli kääntynyt puolittain
poispäin minusta ja seisoi nyt käsi lanteella, iso pää takakenossa ja
hieman sivulle kallellaan ja kasvoillaan jäätävä, paheksuvan
ihmettelevä ilme.

»Herra de Lesperon, en voi muuta kuin lausua kummastukseni


teidän julkeutenne johdosta. Jos kohta olemmekin olleet tuttuja
ennen, niin onko siinä mielestänne minulle tarpeeksi syytä puristaa
kättänne nyt, kun olette laittanut itsenne sellaiseen asemaan, että
hänen majesteettinsa uskollisen palvelijan on mahdotonta tuntea
teitä?»

Astahdin askeleen taaksepäin; järkeni jaksoi tuskin käsittää, mitä


hänen selittämätön käytöksensä merkitsi.

»Minulleko näin, Chatellerault?» ällistelin.

»Teillekö?» kivahti hän, äkkiä kiihtyen. »Mitä muuta sitten odotitte,


herra de Lesperon?»

Olin syyttämäisilläni häntä valehtelijaksi ja selittämäisilläni sitten


hänet alhaiseksi huijariksi ja juonittelijaksi. Mutta samalla kertaa kuin
se ajatus välähti mieleeni käsitin myöskin, kuinka hyödytön sellainen
purkaus olisi. Ja pelkäänpä seisoneeni hänen ja hänen seuralaistensa
— niiden joukossa ilkkuvan St. Eustachen — edessä perin typerän
näköisenä.

»Ei ole mitään muuta mainitsemisen arvoista», mutisin vihdoin.

»Kyllä on!» tokaisi hän. »On paljon muutakin sanottavaa. Saatte


vielä tehdä tiliä petollisuudestanne, ja minua peloittaa, kapinoitsija-
raukka, että kaunis päänne saa erota komean ruumiinne seurasta.
Kohtaamme toisemme Toulousessa. Enemmät puhuttavat puhutaan
sikäläisessä tuomioistuimessa.»

Sokean raivonpuuskan vallassa syöksähdin pöydän yli ja tartuin


tuon viheliäisen lurjuksen kurkkuun, ennenkuin kukaan ennätti edes
ojentaa kättään estääkseen minua.

Hän oli raskas mies, joskin lyhyt, ja hänen tanakka vartalonsa oli
suorastaan tavattoman jäntevä. Mutta vimma antoi silloin minulle
niin rajut voimat, että nykäisin hänet jaloiltaan, ikäänkuin hän olisi
ollut heikko vätys. Kiskaisin hänet pitkälleen pöydälle ja pehmitin
sitten hänen naamaansa sydämeni pohjasta ja suureksi
nautinnokseni.

»Te valehtelija, te roisto, te varas?» ärjyin ikäänkuin jokin raivoava


sekasikiö. »Kuningas saa kuulla tästä, te lurjus! Kautta Jumalan, hän
saa!»

Vihdoin he repivät minut irti hänestä — hänen seuralaiskätyrinsä,


ja pidellen minua varsin kovakouraisesti viskasivat he minut
sätkyttelemään sahajauhoilla peitetylle lattialle. On enemmän kuin
todennäköistä, että he olisivat muitta mutkitta tappaneet minut,
jollei Castelroux olisi tullut väliin.

Mutta syytäen kokonaisen tulvan kirosanojaan, kuten Mordieu,


Sangdieu ja Po' Cap de Dieu, hypähti pieni gascognelainen pitkällään
olevan ruumiini eteen ja käski heitä kuninkaan nimessä ja henkensä
uhalla peräytymään.

Chatellerault oli saanut ankaran läksytyksen ja vaipunut tuoliin,


kasvot purppuranpunaisina, veren valuessa hänen nenästään.
Vasta tuntia myöhemmin, kun olimme taaskin satulassa ja
ratsastimme matkamme viimeistä osaa, annoin Castelrouxille
selityksen näennäisesti mielipuolisesta hyökkäyksestäni
Chatelleraultin kimppuun.

»Menettelitte perin harkitsemattomasti ja epäviisaasti, monsieur»,


huomautti hän surumielisesti, ja vastaukseksi siihen kerroin hänelle
koko jutun. Olin jo nauttiessamme illallista päättänyt tehdä sen, sillä
nyt panin koko toivoni Castelrouxiin, ja ratsastaessamme syyskuisen
yön tähtien valossa ilmaisin hänelle, ken olin.

Kerroin hänelle, että Chatellerault tunsi minut, ja ilmoitin hänelle,


että olimme lyöneet vetoa — salaten kuitenkin vedon luonteen
yksityiskohdat — jonka johdosta olin tullut Languedociin ja joutunut
siihen asemaan, jossa hän oli minut löytänyt ja vanginnut. Aluksi hän
epäili eikä oikein uskonut minua, mutta kun vakuutuksieni kiivaus
samoin kuin itse vakuutuksenikin saivat hänet niihin luottamaan,
lausui hän mielipiteensä kreivi de Chatelleraultista sillä tavalla, että
sydämestäni miellyin häneen.

»Kuten näette, paras Castelroux, olette nyt viimeinen toivoni»,


sanoin.

»Kovin heikko toivo, hyvä herra», huokasi hän.

»Eipä suinkaan, saattaa olla toisinkin. Taloudenhoitajani


Rodenardin ja parinkymmenen palvelijani pitäisi olla jossakin tämän
paikan ja Pariisin välillä. Etsittäkää heitä, monsieur, ja rukoilkaamme
Jumalaa, että he vielä olisivat Languedocissa ja että heidät
löydettäisiin ajoissa!»
»Se tapahtuu, monsieur, lupaan sen teille», vastasi hän
juhlallisesti. »Mutta kehoitan teitä olemaan toivomatta siitä liikaa.
Chatelleraultin vallassa on toimia ripeästi, ja saatte olla varma siitä,
ettei hän vitkastele vähääkään kaiken sen jälkeen, mitä on
tapahtunut.»

»Mutta meillä lienee sittenkin aikaa pari, kolme päivää, ja sillä


välin on teidän, ystäväni, tehtävä voitavanne.»

»Saatte luottaa minuun», lupasi hän.

»Ja siihen mennessä, Castelroux», varoitin, »ette puhu tästä


sanaakaan kellekään.»

Hän vakuutti minulle pitävänsä asian salassa, ja pian välkkyivät


edessämme määräpaikkamme valot.

Sinä yönä viruin Toulousen ummehtuneessa, synkässä vankilassa,


eikä seuranani pimeinä, unettomina tunteina ollut toivon
hiventäkään.
XII

TOULOUSEN TUOMIOISTUIN

Olin toivonut saavani virua joitakuita päiviä vankilassa, ennenkuin


minut vietäisiin oikeuteen; sillä välin olisi kenties Castelrouxin
onnistunut löytää ne henkilöt, jotka voisivat todistaa, kuka olin.
Voitte senvuoksi jossakin määrin käsittää säikähdystäni, kun minut
kutsuttiin tuomarieni eteen seuraavana päivänä ennen puoltapäivää.

Vankilasta vietiin minut oikeussaliin kahleissa kuten tavallinen


varas — sillä lain mukaan oli sellaisen henkilön, jota syytettiin
samasta rikoksesta kuin minua, kannettava tämä häväistys. Noin
parinsadan askeleen päässä oikeussalin portailta näin tungoksesta
äkkiä kasvot, jotka saivat minut pysähtymään hämmästyneenä. Se
tuotti minulle töytäyksen selkään erään vartijani keihään nupista.

»Mikä teitä nyt vaivaa?» karjaisi mies ärtyneesti. »Eteenpäin,


monsieur le traitre!»

Lähdin liikkeelle, tuskin huomaten vartijan raakuutta; katseeni oli


yhäti kiintynyt noihin kasvoihin — Roxalannen kalpeihin, surkeihin
kasvoihin. Hymyilin hänelle lohduttavasti ja rohkaisevasti, mutta
minun hymyillessänikin näytti hänen piirteittensä kauhistunut ilme
käyvän voimakkaammaksi. Kun sitten astelin edelleen, katosi hän
näkyvistäni, ja minä jäin arvailemaan, mitkä syyt olivat tuoneet
hänet uudelleen Toulouseen. Toivoiko hän voivansa jossakin määrin
korjata aiheuttamaansa pahaa? Voi, lapsi-rukka! Jos hän toivoi
sellaista, niin pahasti pelkäsin hänen surkeasti pettyvän.

Kuulustelu tapahtui salaisesti sinetinvartijan johdolla; hän oli laiha,


kuihtunut mies, joka oli yhtä homehtuneen ja kuivan näköinen kuin
pergamentit, joiden keskellä hän oli viettänyt elämänsä. Hänen
apunaan oli kuusi tuomaria, ja hänen oikealla puolellaan istui
kuninkaan käskynhaltija, herra de Chatellerault, jonka mustelmainen
ulkomuoto oli osoittamassa, että me olimme kohdanneet toisemme
vasta eilen.

Kun minulta oli tiedusteltu nimeäni ja asuinpaikkaani, herätin


jonkun verran hämminkiä vastaamalla rohkeasti: »Olen sieur Marcel
de St. Pol, Bardelysin markiisi, Bardelysistä, Picardiesta.»

Puheenjohtaja — se on sinetinvartija — katsahti kysyvästi


Chatelleraultiin. Mutta kreivi vain hymyili ja osoitti sormellaan
jotakin kirjoitettua paperia, joka oli levitettynä pöydällä.
Puheenjohtaja nyökkäsi.

»Herra René de Lesperon», hän lausui, »kenties ei tuomioistuin


voi ratkaista, onko lausuntonne tahallinen yritys harhauttaa tai tehdä
tyhjiksi oikeuden päämäärät vai oletteko te valitettavan
mielisairauden uhri, mikä saattaisi olla seurauksena joko
haavastanne tai Jumalan lähettämänä rangaistuksena
petoksestanne. Mutta tuomioistuin toivoo teidän käsittävän, että sillä
on varmat tiedot siitä, ken olette.»
Syntyi hiljaisuus, jonka aikana muut tuomarit nyökäyttelivät
päätään, filosofisesti hyväksyen puheenjohtajansa sanat. Minä
puolestani pysyin vaiti, oivaltaen kuinka turhaa minun olisi edelleen
panna vastalausettani ja odottaen seuraavaa kysymystä.

»Teidät vangitsi, monsieur, Lavédanin linnassa kaksi päivää


takaperin rakuunajoukkue, jota johti kapteeni de Castelroux. Onko
asia niin?»

»Kyllä, monsieur.»

»Ja kun teidät vangittiin, kun teidät pidätettiin René de


Lesperonina, ette millään tavoin koettanut kieltää olevanne hän,
vaan päinvastoin, kun herra de Castelroux kysyi herra de Lesperonia,
astuitte te esiin ja tunnustitte olevanne hän.»

»Anteeksi, monsieur. Tunnustin, että minut tunnettiin sillä


nimellä.»

Puheenjohtaja naurahti häijysti, ja apulaiset hymyilivät,


kohteliaasti kuvastaen hänen mielialaansa.

»Tämä terävä erittely, monsieur, on ominaista sellaisille henkilöille,


joiden sieluntila ei ole terve», hän selitti. »Mutta minä pelkään, että
siitä ei ole paljoa apua. Yleensä mies tunnetaan nimellään. Teitä,
herra de Lesperon, syytetään valtiopetoksesta sen pahimmassa ja
pahanilkisimmässä muodossa. Teitä syytetään aseellisesta taistelusta
hänen majesteettiansa vastaan. Onko teillä mitään sanomista?»

»Minulla on sanottavaa se, monsieur, että syytös on väärä; hänen


majesteetillaan ei ole uskollisempaa ja alttiimpaa alamaista kuin
minä olen.»
Puheenjohtaja kohautti olkapäitään, ja harmistumisen varjo lehahti
hänen kasvoilleen.

»Jos tarkoituksenne tänne tullessanne on ollut vain kieltää minun


esittämiäni lausuntoja, niin pelkään, että me vain tuhlaamme aikaa»,
hän huudahti kärtyisästi. »Jos haluatte, voin kutsua herra de
Castelrouxin vannomaan, ettette te silloin, kun teidät vangittiin
syytettynä tästä rikoksesta, millään tavoin koettanut torjua
syytöstä.»

»En luonnollisestikaan, monsieur», kivahdin, jonkun verran


kiivastuen tästä tärkeiden tosiasioiden nähtävästi tahallisesta
syrjäyttämisestä, »koska ymmärsin, että herra de Castelrouxin
tehtävänä oli vangita minut eikä tuomita minua. Herra de Castelroux
oli upseeri eikä oikeusistuin, ja jos olisin jotakin hänelle kieltänyt,
olisi se ollut turhaa sanojen haaskaamista.»

»Niinkö? Se on perin sukkelaa; perin sukkelaa todellakin, herra de


Lesperon, mutta tuskin vakuuttavaa. Jatkakaamme! Teitä syytetään
siitä, että olette ollut mukana erinäisissä kahakoissa marsalkkojen
Schombergin ja La Fossen armeijoja vastan ja että te lopuksi olisitte
ollut Castelnaudaryn taistelussa herra de Montmorencyn läheisenä
käskyläisenä. Mitä on teillä sanottavaa?»

»Se ei ole lainkaan totta.»

»Mutta kuitenkin on nimenne, monsieur, luettelossa, joka


löydettiin herra herttua de Montmorencyltä vallattujen
matkatavaroiden seasta.»

»Ei, monsieur», vastasin ylpeästi, »ei ole. Kuinka voi se seikka,


että Lesperon-nimi on löydetty herttua de Montmorencyn papereista,
todistaa minut syypääksi valtiopetokseen, koska olen sanonut teille,
etten ole Lesperon? Jos teillä, messieurs, olisi hiukankaan tuntoa
siitä, mitä korkea tehtävänne vaatii, pyytäisitte minua selittämään,
miten minut on voitu sekoittaa Lesperoniin ja vangita hänen
sijastaan, jos kerran väitteeni ovat todenperäisiä. Sitten, messieurs,
voisitte koettaa ottaa selvää, ovatko sanani paikkansapitäviä. Mutta
tällainen menettely, jota nyt noudatatte, ei ole tuomitsemista, vaan
murhaa. Oikeutta kuvataan hyveelliseksi naiseksi, jonka silmillä on
side ja joka pitää kädessään puolueetonta vaakaa; teidän
käsissänne, hyvät herrat, on siitä, sieluni autuuden nimessä, tullut
huntua kouristeleva portto.»

Chatelleraultin kyynillinen hymy kävi leveämmäksi sitä mukaa kuin


puheeni jatkuessaan lietsoi raivoa noiden kunnianarvoisten
herrasmiesten sydämissä. Sinetinvartija vuoroin kalpeni, vuoroin
punastui, ja kun minä vaikenin, syntyi painostava hiljaisuus, jota
kesti joitakuita hetkisiä. Vihdoin puheenjohtaja kallistui
neuvottelemaan kuiskaamalla Chatelleraultin kanssa. Sitten hän kysyi
minulta pakotetun rauhallisella äänellä, joka muistutti ukkoshauteen
tyyneyttä:

»Kuka te väitätte olevanne, monsieur?»

»Olen sen jo kerran teille sanonut ja rohkenenpa uskoa, ettei


nimeni niin helposti unohdu. Olen sieur Marcel de St. Pol, Bardelysin
markiisi, Bardelysistä, Picardiesta.»

Hänen ohuet huulensa raottuivat ovelaan hymyyn.

»Onko ketään, joka voi todistaa, kuka olette?»


»Satoja, monsieur!» vastasin innokkaasti, luullen pelastuksen jo
olevan käteni ulottuvilla.

»Mainitkaa heistä joitakuita!»

»Mainitsen yhden — sellaisen, jonka sanaa ette uskalla epäillä.»

»Nimittäin?»

»Hänen majesteettinsa kuninkaan. Olen kuullut, että hän on


matkalla Toulouseen, ja pyydän teitä vain odottamaan hänen
saapumistaan, ennenkuin jatkatte juttuni käsittelyä.»

»Ettekö saata ajatella ketään muuta todistajaa, monsieur, sellaista,


joka voitaisiin saada esiintymään nopeammin? Sillä jos todella voitte
näyttää olevanne se, joksi itseänne väitätte, niin miksi viruisitte
vankilassa muutamia viikkoja?»

Hänen äänensä oli mairittelevan ystävällinen. Siitä oli suuttumus


tyyten kadonnut, ja minä — hupsu — kuvittelin mielessäni sen
aiheutuneen siitä, että mainitsin kuninkaan.

»Ystäväni, herra sinetinvartija, ovat kaikki joko Pariisissa tai hänen


majesteettinsa matkueessa, eivätkä niin ollen todennäköisesti saavu
tänne ennen häntä. Taloudenhoitajani Rodenard ja palvelijani —
parikymmentä heistä — ovat kenties vielä Languedocissa, ja toivoisin
teidän etsittävän heitä. Heidät saataisiin mahdollisesti käsiin
muutamissa päivissä, jolleivät he vielä ole päättäneet palata Pariisiin,
uskoen minut kuolleeksi.»

Hän hieroi miettivästi leukaansa, kohottaen katseensa auringon


valaisemaan, lasiseen kupukattoon.
»Ahh!» hän äänsi. Se oli pitkäveteinen huokaus, joka johtui
pahoittelusta, päätelmästä tai väsymyksestä ja kärsimättömyydestä.
»Eikö Toulousessa ole ketään, joka voisi vannoa, kuka olette,
monsieur?» kysyi hän.

»Pelkään, ettei ole», vastasin. »Tietääkseni ei ketään.» Kun


lausuin ne sanat, muuttui puheenjohtajan ilme jyrkästi, ikäänkuin
hän olisi riisunut naamarin kasvoiltaan. Äskettäin hän oli ollut
kissamaisen mairea; nyt hän äkkiä kävi rajuksi kuin tiikeri. Hän
karkasi pystyyn, kasvot tulipunaisina, silmät liekehtien, ja hänen
puheensa tuli nyt kiihkeänä, sekavana, melkein katkonaisena
tulvana.

»Miserable!» hän mylvi, »te itse olette omilla sanoillanne


todistanut syyllisyytenne. Kuvittelitteko mielessänne, että kenties
kuningas sillä aikaa, kun me noudattaisimme Pariisista todistajianne,
väsyisi oikeudenkäyttöön ja lempeyden puuskassa julistaisi yleisen
armahduksen? Mutta oikeutta, mieletön, ei voida eksyttää. Jos
olisitte todella ollut Bardelys, niin olisitte nähnyt, että täällä, tässä
salissa, istuu eräs herrasmies, joka on hänen hyvin läheinen
tuttavansa. Hän on tuossa, monsieur; hän on herra kreivi de
Chatellerault, josta lienette kuullut puhuttavan. Mutta kun kysyin
teiltä, onko Toulousessa ketään, joka voisi todistaa, ken olette,
vastasitte te, ettei tietääksenne ollut ketään. Enää en salli teidän
kuluttaa aikaani, siitä saatte olla varma.»

»Hyvät herrat», aloin puhua, »nämä johtopäätökset tuntunevat


teistä ilmeisen selviltä, mutta saatte uskoa minua, ne ovat pettäviä.
Tunnen herra de Chatelleraultin varsin hyvin samoin kuin hän minut,
ja jos hän vain haluaisi puhua totta ja esiintyä miehenä ja
herrasmiehenä, niin hän sanoisi teille, että minä todella olen
Bardelys. Mutta herra kreivillä on omat tarkoituksensa toimittaessaan
minut tuomituksi. Osaksi on juuri hänen syytään, että minä olen
joutunut tähän asemaan ja minut on sekoitettu Lesperoniin. Mitä
hyötyä minulla olisi niin ollen ollut, jos olisin vedonnut häneen?
Mutta kuitenkin, herra puheenjohtaja, hän on synnyltään herrasmies,
ja hänellä lienee vielä jonkun verran kunniantuntoa, kysykää häneltä
monsieur — kysykää häneltä suoraan, olenko minä Marcel de
Bardelys vai enkö!»

Luja sävyni tehosi noihin heikkoluonteisiin miehiin. Menipä


puheenjohtaja niin pitkälle, että loi kreiviin päin kysyvän katseen.
Mutta Chatellerault, joka hillitsi itseään erinomaisesti, kohautti
olkapäitään ja hymyili säälittelevää, ikävystynyttä hymyä.

»Onko minun todella vastattava sellaiseen kysymykseen, herra


puheenjohtaja?» Hänen äänensä ja ilmeensä osoittivat selvästi,
kuinka vajavaisena hän pitäisi puheenjohtajan älyä, jos hänet
pakotettaisiin tekemään se.

»Eihän toki, herra kreivi», vastasi puheenjohtaja hätäisesti,


hyläten halveksivasti sellaisen ajatuksen. »Se ei ole missään nimessä
tarpeellista.»

»Mutta kysymys, herra puheenjohtaja!» jyräytin minä. »Kysykää


häneltä — jos teillä on vähääkään velvollisuudentuntoa — kysykää
häneltä, enkö ole Marcel de Bardelys!»

»Hiljaa!» karjaisi puheenjohtaja minulle. »Enää ette saa pitää


meitä narrinanne, te sukkelapäinen valehtelija!»

Pääni painui alas. Tuo kurja oli totisesti tuhonnut viimeisenkin


toiveeni.
»Vielä kerran, monsieur», virkoin hyvin tyynesti, »sen vannon,
maksaa tämä käytöksenne ja nämä aiheettomat solvaukset teille
virkanne. Rukoilkaa Jumalaa, etteivät ne maksa myöskin päätänne!»

He ottivat sanani yhtä keveästi kuin lapsen uhkaukset otetaan. Se


seikka, että tulin maltittomuudessani ne lausuneeksi, oli vain omiaan
tekemään tuomioni vielä varmemmaksi, jos siihen yleensä enää
mitään tarvittiin.

Käyttäen minusta monia häpäiseviä nimityksiä, joita tavallisesti


käytetään mitä pahimmista rikollisista, he tuomitsivat minut
kuolemaan. Mieli painuksissa, pitäen itseäni tuhon omana ja
varmana siitä, että minut vietäisiin mestauspölkylle aivan
lähitunteina, annoin vartijoiden kuljettaa minut Toulousen katuja
pitkin takaisin vankilaan.

Olin ollut puoli tuntia kopissani, kun ovi avautui ja sisään astui
Castelroux, jota en ollut nähnyt senjälkeen kuin edellisenä yönä. Hän
tuli valittamaan kovaa osaani ja samalla kehoittamaan, etten vielä
tyyten menettäisi toivoa.

»Tänään on liian myöhäistä panna tuomiota toimeen», hän selitti,


»ja kun huomenna on sunnuntai, siirtyy se ylihuomiseen. Siihen
mennessä saattaa tapahtua paljon, monsieur. Asiamiehiäni on
liikkeellä ympäri koko maakunnan etsimässä palvelijoitanne, ja
rukoilkaamme luojaa, että heidän onnistuisi ne löytää.» Sitten hän
lisäsi, ettei se kuitenkaan ollut hänen käyntinsä ainoa syy. Eräs
nainen oli saanut sinetinvartijalta luvan käydä minua katsomassa ja
odotti parhaillaan puheillepääsyä.

»Nainen!» huudahdin ja mieleeni välähti Roxalanne. »Neiti de


Lavédanko?» kysäisin. Hän nyökkäsi.
Pyysin häntä päästämään vieraani heti sisään, ja pian oli
Roxalanne luonani. Castelroux sulki poistuessaan oven, ja me
jäimme kahdenkesken.

Seisoimme hetkisen vastakkain sanaakaan virkkamatta. Sitten hän


loi katseensa maahan, astui askeleen eteenpäin ja sopersi änkyttäen,
empien, tukahdutetusti:

»Monsieur, monsieur.»

Yhdellä hyppäyksellä olin hänen edessään sulkien hänet syliini ja


painaen hänen pienen, ruskean päänsä olkaani vasten.

»Roxalanne!» kuiskasin niin hyväilevästi kuin voin. »Roxalanne!»


Mutta hän koetti irtautua syleilystäni.

»Antakaa minun olla, monsieur!» hän rukoili, ääni omituisesti


väristen.
»Älkää koskeko minuun, monsieur! Te ette tiedä — ette tiedä.»

»Kyllä minä tiedän, rakas», kuiskutin, »ja myöskin ymmärrän.»

Sen kuultuaan hän lakkasi heti ponnistelemasta ja tuntui olevan


sylissäni hervottomana, ja avuttomana.

»Tiedättekö, monsieur?» hän kysyi, »tiedättekö, että juuri minä


kavalsin teidät?»

»Kyllä», vastasin suoraan.

»Ja voitte antaa sen anteeksi? Minä aiheutan kuolemanne, ettekä


te moiti minua! Oi, monsieur, se tappaa minut!»
»St, lapsi! Ymmärrän sen», vastasin, silittäen hänen ruskeata
tukkaansa.

»Ette aivan, monsieur. Rakastin teitä niin, monsieur, ettette voi


aavistaakaan, kuinka kärsin sinä aamuna, jolloin neiti de Marsac tuli
Lavédaniin.

— Aluksi se oli vain tuskaa ajatellessani, että menettäisin teidät,


että te katoaisitte elämästäni, etten enää teitä näkisi — teitä, jonka
olin laskenut niin lähelle sydäntäni.

— Nimitin sinä aamuna itseäni pikku hupakoksi, kun olin


uneksinut, että te muka piditte minusta. Turhamaisuuteni, ajattelin,
oli narrannut minut haaveilemaan, että käytöksenne minua kohtaan
oli rakastavan hellää. Olin katkeroitunut itseäni kohtaan ja kärsin —
oi, niin kovasti! Kun sitten myöhemmin olin ruusutarhassa, tulitte te
luokseni.

— Muistattehan, kuinka otitte minut kiinni ja osoititte, ettei yksin


turhamaisuus ollut johtanut minua harhaan. Olitte pettänyt minua,
arvelin. Silläkin hetkellä luulin teidän pettävän minua. Te kohtelitte
minua kevytmielisesti ettekä välittänyt mitään kärsimyksistäni,
kunhan minusta vain oli teille hiukan huvia lyhentämään joutenolon
yksitoikkoisuutta oleskellessanne meillä.»

»Roxalanne — oma Roxalanne-parkani!» mutisin.

»Sitten muuttui katkeruuteni ja suruni vihaksi teitä vastaan. Te


olitte murtanut sydämeni ja luulin teidän tehneen sen vain leikillä.
Siitä päätin rangaista teitä. Ah! eikä se kenties ollut ainoastaan sitä.
Luultavasti kannusti minua jonkun verran myöskin mustasukkaisuus.
Te olitte kevytmielisesti kosiskellut minua, mutta te olitte saanut
minut rakastumaan itseenne, ja jollen minä teitä saisi, ei teitä saisi
kukaan muukaan. Ja niin minä hulluna lähdin Lavédanista, sanoen
isälleni meneväni Auchiin hänen sisarensa luokse, tulin Toulouseen ja
annoin teidät ilmi sinetinvartijalle.

— Tuskin olin ehtinyt sen tehdä, kun jo tajusin tekoni kauheuden


ja aloin vihata itseäni.»

Hän vavahti, ja häneltä pääsi huokaus.

»He eivät saa panna sitä täytäntöön! Oi, he eivät saa! Sanokaa
minulle, että voitte puolustautua, ettette ole se mies, joksi he teitä
luuleva!»

»Olemme Jumalan kädessä, lapsi. Mahdollisesti voin vielä pelastaa


itseni. Jos pelastun, tulen suoraa päätä luoksenne, ja te saatte tietää
kaikki. Mutta muistakaa, lapsi», ja nostaen käsilläni hänen kasvojaan
katsoin hänen sinisiin, kyyneleisiin silmiinsä — »muistakaa, pieni,
että yhdessä asiassa olen ollut vilpitön ja kunniallinen, siinä ei
minulla ole ollut mitään muuta vaikutinta kuin sydämeni —
kosiessani teitä. Minä rakastan teitä, Roxalanne, kaikesta sielustani,
ja jos kuolen, olette te koko maailmassa ainoa olento, jonka
jättäminen minua surettaa.»

»Minä uskon sen; uskon varmasti. Ei mikään voi enää horjuttaa


uskoani.
Mutta ettekö tahdo sanoa minulle, kuka olette?»

Mietin taaskin hetkisen. Sitten pudistin päätäni.

»Odottakaa, lapsi», virkoin, ja hän noudatti toivomustani eikä


enää kysellyt.
Toisen kerran löin silloin laimin sopivan tilaisuuden enkä
tunnustanut, ja kuten olin katunut sitä, että olin antanut
ensimmäisen tilaisuuden mennä käyttämättä ohitseni, sain myöskin
katua tätä vaikenemistani, vieläpä edellistä katkerammin.

Hän viipyi vielä hetkisen luonani, ja minä koetin valaa rohkeutta


hänen sieluunsa. Puhuin toiveistani, jotka perustuivat siihen, että
Castelroux löytäisi ystäviäni tuntemaan minua, vaikka ne toiveet
olivat varsin heikot. Ja myöskin hän, lapsi-parka, koetti lohduttaa ja
rohkaista minua.

»Jospa kuningas olisi täällä!» hän huokasi. »Menisin hänen


puheilleen ja rukoilisin polvillani, että teidät vapautettaisiin. Mutta
hänen kerrotaan olevan vasta Lyonsissa, enkä voisi mitenkään
ennättää käydä siellä maanantaihin mennessä. Menen uudelleen
sinetinvartijan luokse ja pyydän häntä armahtamaan tai ainakin
lykkäämään tuomion toimeenpanoa.»

En riistänyt häneltä toivoa; en virkkanut mitään siitä, kuinka


hyödytöntä se olisi. Mutta pyysin häntä viipymään Toulousessa
maanantaihin saakka, että hän voisi käydä luonani ennen loppua, jos
loppua ei voitaisi välttää.

Sitten saapui Castelroux saattamaan häntä pois, ja me erosimme.


Mutta olin saanut häneltä paljon lohtua, paljon rohkeutta ja voimaa.
Minusta tuntui, että jos kohtaloni olisi astua mestauslavalle, voisin
sen nyt tehdä reippaammin ja iloisemmin.
XIII

YHDENNELLÄTOISTA HETKELLÄ

Castleroux kävi luonani seuraavana aamuna, mutta ei tuonut


mitään sellaisia uutisia, joita olisi voinut pitää ilahduttavina. Hänen
tiedustelijoistaan ei yksikään ollut vielä palannut, eikä kukaan heistä
ollut lähettänyt sanaa siitä, että olisi päässyt seuralaisten jäljille.
Rohkeuteni lamaantui hieman, ja nekin vähäiset toiveet, joita minulla
vielä oli, haihtuivat nopeasti.

Päätin vihdoin kyhätä täydellisen selostuksen tapahtumista ja


pyytää Castelrouxia huolehtimaan siitä, että se annettaisiin
kuninkaalle itselleen. Siten tulisivat oikeuden vaatimukset
tyydytetyiksi, ja lisäksi saisin — vaikka myöhään — maksaa velkani
kreiville.

Tehtyäni sen päätöksen aioin juuri aloittaa kirjoittamisen, kun


huomioni kiintyi harvinaiseen ääneen. Aluksi se oli vain epäselvää
kohinaa, ikäänkuin aaltojen pauhua rantaa vasten. Vähitellen sen
voima kasvoi, ja siitä alkoi erottua ihmisääniä, riemuisia
tervehdyshuutoja. Sitten kuului väestön melun ylitse tykinlaukauksen
pamahdus, sitten toinen, ja vielä toinen.
Hypähdin pystyyn, ihmetellen mitä oli tekeillä, ja riensin
ristikkoisen ikkunani ääreen kuuntelemaan.

Kun väkijoukko siirtyi lähemmäksi, alkoi minusta tuntua, että


huudot olivat suosionosoituksia.

Mieleeni välähti, että joku korkea henkilö saapui Toulouseen, ja


ensimmäiseksi juolahti mieleeni kuningas. Sellaista mahdollisuutta
ajatellessani huimasi päätäni ja toivo sumensi järkeni. Seuraavalla
hetkellä muistin Roxalannen viime yönä kertoneen, että kuningas, oli
vasta Lyonsissa asti. Torjuin senvuoksi sen ajatuksen ja sen mukana
toivonikin, sillä olisi ihme, jos kuningas, matkustaen mukavaan,
velttoon tapaansa, joka oli kuvaavaa koko hänen toiminnalleen,
joutuisi Toulouseen ennenkuin viikko olisi kulunut, ja nythän oli vasta
sunnuntai.

Palasin kirjoittamaan ja odottamaan, kunnes saisin tietää hälinän


syyn vartijaltani, kun hän seuraavan kerran tulisi luokseni.

Oli kulunut kenties tunnin verran aikaa, kun ovi avautui ja


kynnykseltä tervehti minua Castelrouxin hilpeä ääni.

»Monsieur, olen tuonut erään ystävän luoksenne.»

Pyörähdin ympäri tuolissani ja yksi vilkaisu Castelrouxin vieressä


seisovan nuorukaisen yleviin, siroihin kasvoihin ja vaaleaan tukkaan
sai minut äkkiä hypähtämään pystyyn.

»Mironsac!» kiljaisin ja juoksin kädet ojossa häntä vastaan.

Mutta vaikka riemuni olikin suuri ja hämmästykseni voimakas, oli


Mironsacin kasvoilla kuvastuva hämminki vieläkin ilmeisempi.
»Herra de Bardelys!» huudahti hän, ja hänen kummastuneessa
katseessaan oli sata kysymystä.

»Po Cap de Dieu!» murahti hänen serkkunsa. »Taisinpa totisesti


tehdä viisaasti, kun toin sinut tänne.»

»Mutta», tiedusti Mironsac serkultaan, tarttuen käsiini, »miksi et


ilmoittanut minulle, Amedée, että aioit opastaa minut herra markiisi
de Bardelysin luokse?»

»Olisitko tahtonut minun turmelevan näin iloista yllätystä?» vastasi


serkku.

»Armand», sanoin minä, »ei milloinkaan ole kukaan ollut


tervetulleempi kuin sinä nyt. Tulit parhaiksi ajoissa pelastamaan
henkeni.»

Sitten kerroin, vastaillen hänen kysymyksiinsä, lyhyesti kaikki, mitä


minulle oli tapahtunut sen yön jälkeen, jolloin veto Pariisissa lyötiin,
ja kuinka Chatelleraultin ovela vaikeneminen oli saattanut minut
mestauslavan kynnykselle. Sen kuullessaan hän vimmastui, ja
mieltäni hiveli, kun hän sätti kreiviä. Vihdoin hillitsin hänen herjaavaa
purkaustaan.

»Saakoon riittää tällä kertaa, Mironsac!» sanoin nauraen. »Sinä


olet täällä ja voit tehdä tyhjiksi kaikki Chatelleraultin suunnitelmat
todistamalla sinetinvartijalle, kuka olen.»

Mutta sitten valtasi minut epäilys, ikäänkuin olisi kylmä käsi


laskeutunut päähäni. Käännyin Castelrouxiin päin ja huudahdin.

»Mon Dieu! Entä jos he eivät suostu ottamaan asiaani uudelleen


käsiteltäväksi?»

You might also like