文档库 最新最全的文档下载
当前位置:文档库 › The implementation of the Gofer functional programming system

The implementation of the Gofer functional programming system

The implementation of the Gofer functional programming system
The implementation of the Gofer functional programming system

The implementation of the Gofer functional programming system

Mark P.Jones

Yale University,Department of Computer Science,

P.O.Box208285,New Haven,CT06520-8285.

jones-mark@https://www.wendangku.net/doc/e411768419.html,

Research Report YALEU/DCS/RR-1030May1994

Abstract

The Gofer system is a functional programming en-vironment for a small,Haskell-like language.Sup-porting a wide range of di?erent machines,including home computers,the system is widely used,both for teaching and research.

This report describes the main ideas and techniques used in the implementation of Gofer.This informa-tion will be particularly useful for work using Gofer as a platform to explore the use of new language features or primitives.It should also be of interest to those cu-rious to see how the general techniques of functional programming language compilation are adapted to a simple,but practical,implementation. Introduction

The Gofer system is a functional programming envi-ronment for a small,Haskell-like language.The lan-guage can be characterized by its support for lazy evaluation and higher-order functions,and a static type system that includes both polymorphism and overloading.First released in September1991,Gofer is widely used,both for education and research.Judg-ing from comments from its users,there are two main reasons for Gofer’s popularity.First,that it runs on a wide range of machines,including small home com-puters.Second,particularly on more powerful sys-tems,the interpreter provides a fast,interactive de-velopment environment,avoiding the need for lengthy recompilation.

While the user documentation[24]and C source code for Gofer have always been included in public dis-tributions,there was no substantial e?ort to pro-vide details about the implementation.At the time, this seemed unnecessary;although it introduced some new ideas,most of the techniques used were believed to be standard and well-known.In retrospect,user feedback during the past few years suggests that some of these ideas may not be as well-known as we had expected.There has also been quite a lot of interest in modifying the Gofer system,from simple tasks such as the addition of new primitives, to more sophisticated experiments in language design. While this information can,in principle,be gleaned by a careful study of the source code,it is certainly not the most convenient form of documentation! This report is intended as a guide for those interested in the inner workings of Gofer.Its aim is to explain the original design goals,the overall structure,the datatypes used,and the way that the di?erent pieces ?t together.It does not attempt to cover every tech-nical detail of the system and should be viewed as an introduction,not a replacement,for studies of the source code.Nor is this report intended as a tutorial on‘the implementation of functional languages’;in-deed,Simon Peyton Jones’book by that name[48] was a constant companion during the development of Gofer,and remains an almost certain prerequisite to this report.

Throughout this report,we assume familiarity with the Gofer environment as described in the user docu-mentation[24,25,32],with the Haskell functional programming language on which much of the lan-guage design is based[16],and with the C program-ming language in which the system is implemented. Outline of report

We begin in Section1,outlining the principal design goals for the development of the Gofer system.Sec-tion2summarizes the main features of the system from the user’s perspective,highlighting some of the decisions made in the design of the standard user in-terface.In Section3,we begin a more detailed study of the current implementation of Gofer.Starting with an overview of the whole system,we progress through

detailed descriptions of the most important compo-nents including storage management(Section4),lex-ical analysis and parsing(Section5),static analysis (Section6),type checking(Section7),compilation to supercombinators(Section8),and program execution (Section9).Section10discusses some of the ways that functional programming has been used and in?u-enced the development of Gofer,even though the sys-tem was actually written in imperative C.The Gofer compiler,a simple-minded translator producing ex-ecutable C versions of Gofer programs,is described in Section11.Finally,Section12o?ers some re?ec-tions on the current implementation and some areas for future development.

1Motivation and design goals The Gofer system was initially developed as a vehi-cle for personal research.The name Gofer1is derived from the claim that functional languages are suppos-edly‘Good for equational reasoning’,a re?ection on the fact that the system was originally planned as a tool for machine-assisted equational reasoning.The initial design included a small interpreter intended only for simple calculations,but this soon became the main focus of the project,motivated in particu-lar by the desire to investigate a new implementation technique for the Haskell overloading mechanism[21]. The system was designed with some speci?c goals in mind:

?Compatibility:The language design should be closely based on the de?nition of Haskell,an emerging and freely available standard for non-strict functional programming languages[16].Of course,Haskell was also a natural choice for work on type class overloading and guaranteed an ini-tial supply of examples on which to base any comparisons.Finally,it seemed sensible to avoid the notoriously di?cult process of language de-sign,concentrating instead on speci?c elements of a carefully developed system.?Extensibility:The system should provide a good foundation for further work and experimen-tation.

?Portability:The system should be usable on

a wide range of machines.A very speci?c con-

1We were not aware of the similarly named gopher program—used to access information over the Internet—until some time after the?rst release of Gofer.Despite their very di?erent application areas,the choice of names has been an un-fortunate source of confusion,and may soon warrant the choice of a new name for Gofer.

straint was that it should be able to run the system on an8MHz8086based PC with640K RAM running MS-DOS;all of the original devel-opment work was carried out on this machine.

Such systems are infamous for their awkward16 bit segmented architecture that limits the size of individual blocks of data to64K.Although the Gofer system runs on many di?erent machines without such restrictions,this has continued to be an important in?uence on the basic design. Note that,although speed of execution is an impor-tant part of making an implementation usable,we did not consider this as a primary design goal.

Looking back,we believe that we have been reason-ably successful in meeting these goals.Initially based on version1.0of the Haskell report[17],Gofer has been modi?ed to track subsequent versions of Haskell. As a result,there is a large class of programs that can be run using either Haskell or Gofer without requir-ing changes to the source code.Unfortunately,there are some di?erences,most signi?cantly in the treat-ment of type class overloading.It is easier now to realize that the goal of compatibility stands in direct con?ict with the technical ideas that motivated its de-velopment.We still believe that the Gofer approach to type classes has some important advantages,but the incompatibility with Haskell,although minor,has become a little frustrating.The di?erences are also something of an embarrassment,given that one of the goals in the design of Haskell was to‘reduce unneces-sary diversity in functional programming languages’. Gofer has also proved to be useful in subsequent work, and some of these developments have found their way into general releases of the Gofer system.Examples of this include:

?A simple-minded compiler,translating Gofer programs to C to enable the development of stan-dalone applications written in Gofer.

?An system of constructor classes,extending the notion of Haskell type classes,to allow more sophisticated forms of user-de?ned overloading

[33].

Others,for example,the specialized partial evalua-tor described in[31],have yet to be included in the standard distribution.

Finally,the Gofer system has proved to be fairly portable and includes support for a wide variety of di?erent machine and operating system environ-ments.In a few places,the source code depends on assumptions about the compiler used to build Gofer

which cannot be guaranteed by the C language stan-dards.In this respect,we seem to have been fairly lucky that our non-portable assumptions happen to be true for the systems used.Despite the new features added since the?rst release,Gofer can still be used on the same small machines that it was originally de-veloped for.However,most of the machines in use today,even home computers,are much more power-ful.We may see signi?cant bene?ts in future versions of the system once we are free of the constraints that the older machines impose.

The fact that Gofer can be used on small machines seems to be one of the main reasons for its widespread use.However,while some other functional language implementations do require more powerful machines, Gofer is by no means unique in providing a func-tional programming environment for smaller systems; Leroy’s Caml Light[40],implementing a dialect of ML,is another well-known example.

2A user’s perspective

The Gofer system2provides an interpreter for an ex-perimental language that is closely based on the def-inition of Haskell version1.2[16].Notable features include:

?A purely functional language with non-strict semantics(lazy evaluation),higher-order func-tions,pattern matching,...

?Facilities for de?ning new algebraic datatypes and type synonyms.

?A polymorphic type system with provision for user-de?ned overloading based on a system of type classes(see Section7.5for further details).

?Full Haskell expression and pattern syntax in-cluding lambda,case,conditional and let expres-sions,list comprehensions,operator sections,and wildcard,as and irrefutable patterns.

?A partial implementation of the Haskell I/O fa-cilities,supporting simple text?le manipulation and interactive programs.

?User documentation,sample programs and source code freely available by anonymous ftp.?A relatively portable implementation runs on a wide range of computer systems including several smaller home/personal computers.

2This report is based on Gofer version2.30,the current release at the time of writing.Most of the comments in this report are also true of earlier versions.The only signi?cant feature of Haskell that is not cur-rently supported is the Haskell module system.On the other hand,Gofer also supports several exper-imental extensions of which constructor classes are perhaps the best known example.The latest release also includes prototype implementations of other re-cent proposals for extensions to Haskell,including monadic I/O[47]and lazy state threads[39].

In a typical Gofer session,the system behaves like an interactive calculator.First,the user enters an ex-pression at the Gofer prompt,usually a?character. After checking for errors,the interpreter evaluates the expression,lazily printing the result as it is produced, and then returning to the prompt for another expres-sion:

?2*(3+4)

14

(5reductions,10cells)

?sum[1..10]

55

(92reductions,132cells)

?

The counts of reductions and cells give a rough indication of the amount of time and memory used by the calculation,respectively.These statistics can be useful in some situations for comparing the relative complexity of di?erent algorithms.However,these messages can also be suppressed using a command line option to avoid unnecessary distractions.

The process described above has much in common with the standard read-eval-print loop used in many interactive programming environments,particularly those for languages like Lisp and Scheme.Gofer al-lows local de?nitions within an expression,for exam-ple:

?f3where f x=x*x-3*x+7

7

(7reductions,13cells)

?

However,unlike most Lisp systems,it is not possi-ble to de?ne new global values or functions directly from within the interpreter.Instead,new de?nitions are entered using a text editor to produce a script ?le of de?nitions that can then be loaded into the in-terpreter.The strict separation between sessions and scripts was a conscious design decision,inspired by [7]and[58],re?ecting the way we expect the system to be used in practice.In particular,this approach allows a programmer to work by switching between scripts and sessions,adding new de?nitions,testing,

and making further changes as necessary.In addi-tion,script?les provide a consistent view of the cur-rent program,allowing program development to be spread across di?erent Gofer sessions,but also avoid-ing the complexities(and confusions)of incremental compilation and type checking.

The user interface is carefully designed to support this style of program development.For example,if an error is detected while loading a script?le,the user can enter the command:e,an abbreviation for :edit,to start up a text editor on the?le contain-ing the error at the approximate line position where the problem was detected.Once the error has been corrected,the user saves the?le and exits the edi-tor,returning to the interpreter,which automatically reloads the script.

The following example shows how the:load com-mand is used to load the de?nitions in the script?le example.gs into the interpreter:

?:load example.gs

Reading script file"example.gs":

Gofer session for:

/Gofer/Standard.prelude

example.gs

?

Notice that the list of?les displayed here includes not only example.gs,but also a prelude?le called /Gofer/Standard.prelude.This is a script of stan-dard de?nitions that are loaded at the beginning of every Gofer session.For example,the prelude typ-ically includes the de?nition of standard arithmetic and list processing functions.The interpreter allows users to develop special versions of the prelude to suit particular requirements.For example,this fea-ture has been used to support experimental preludes using constructor classes,or to provide closer com-patibility with Haskell,or with a textbook such as [7]in an introductory course on functional program-ming.On the other hand,the system is carefully designed to ensure that the prelude?le will only be loaded once when the interpreter is started.This is intended to discourage users from the temptation of modifying prelude de?nitions;since these de?nitions are usually shared by many di?erent programs,it is bad practice to modify them for the purposes of one particular program.The preferred method for writing new prelude?les is to build the new de?nitions on top of a minimal prelude;the new de?nitions should only be moved into a stand-alone prelude when the devel-opment is complete.It is entirely desirable for this process to be a little awkward;new preludes should only be used as a last resort since they are inherently non-standard.

Although Gofer does not include a module system,it is often convenient to split large programs into sev-eral di?erent script?les.This allows di?erent com-ponents of a program to be developed independently, and perhaps reused in later programs.The Gofer sys-tem supports this by allowing the user to specify a list of script?les,each of which is loaded,stacked on top of the de?nitions in the preceding?les.For example, the following command might be used to load three script?les into the interpreter:

?:load ex1.gs ex2.gs ex3.gs

Since the?les are loaded in strict order,it is possi-ble for ex2.gs to include references to de?nitions in ex1.gs,but not to those in ex3.gs.In a similar way, if the de?nitions in ex2.gs are changed,then both ex2.gs and ex3.gs will be reloaded,since the de?-nitions in the latter might potentially be modi?ed in light of changes in the former.A more sophisticated dependency analysis could be used to avoid reloading ex3.gs in cases where it would not be a?ected by any changes in ex2.gs.However,in practice,the reload-ing of script?les is usually fast enough that this is not a concern.

For convenience,Gofer allows the list of?les required by a particular program to be recorded in a project ?le.A command of the form:

?:project program.prj

can be used to read the?le names listed in program.prj and load the corresponding script?les into the interpreter.

It is important to mention that the original Gofer user interface was closely modeled on the‘scrolling’interface of Orwell[58]which provided my own intro-duction to functional programming.For example,fol-lowing Orwell,early versions of Gofer displayed lines of dots to indicate progress during various stages of reading script?les3.The command syntax of Gofer, using a leading colon character,:,was also modeled on that of the editor vi,versions of which are avail-able for many of the systems on which Gofer is used. In comparison with popular programs on some ma-chines,the user interface of Gofer is very primitive. Unfortunately,there are still many di?erent stan-3This feature is still supported by the current release but requires a command line option,+..It is no longer used as the default behaviour because it has a surprisingly signi?cant slowing e?ect on the total time taken to process script?les on some machines.

dards for constructing more sophisticated user inter-faces and we are not aware of any standard toolk-its o?ering the degree of portability required for the Gofer system.However,several people have devel-oped graphical user interfaces for Gofer,targeted for speci?c machines.The most widely known example is MacGofer which extends the standard Gofer inter-preter with a graphical user interface for Apple Mac-intosh computers.The MacGofer system has been developed by Kevin Hammond at the University of Glasgow.

3Overall structure

After all of the background information given above, it is?nally time to begin our tour through the Gofer system!

3.1Implementation language

One of the?rst decisions to be made was the choice of implementation language.Given that Gofer was intended to run on a wide variety of machines,in-cluding small PCs with limited memory,the C lan-guage was an obvious candidate.Even so,the deci-sion to use C was not easy;we believe that the de-velopment of Gofer would have been both easier,and less error-prone,had it been written in a strongly typed functional language which it accepts.This ap-proach is often used by designers as a means of test-ing,and of demonstrating con?dence,in the use of a new language for program development.For ex-ample,Chalmers LML[4],Standard ML of New Jer-sey[3]and Glasgow Haskell[12]are all able to com-pile their own source code.However,each of these systems requires substantial machine resources.In addition,we were also concerned about bootstrap-ping;each of the systems above relies on a compiler to achieve reasonable performance,while Gofer was originally conceived as an interpreter.Nevertheless, even though Gofer was written in an imperative lan-guage,it also shows strong in?uences from functional programming.This is discussed in a little more detail in Section10.

Although compilers for ANSI C were available at the time,the Gofer code was written so that it could also be compiled with older K&R compilers[37].The C preprocessor was used to allow the use of important features of ANSI C where possible.For example,a preprocessor macro,Args(arglist)is used to allow the use of function prototypes in declarations such as: Void parseScript Args((String,Long));For an ANSI C compiler,the Args macro includes the types of the arguments of parseScript in the declaration,allowing compile-time detection of some argument mismatch errors.For older compilers,the Args macro is de?ned to omit the list of argument types from the preprocessed version of the program. It turns out that many of the datatypes in Gofer are just synonyms for existing C types.For example,the types Int,Text,Cell,List,Pair and Module are just new names for the standard C type of integers, int.However,careful use of these di?erent names provides valuable program documentation,suggest-ing how we intend di?erent values to be treated.For example,the prototype for the copy function de?ned in storage.c is written as:

extern List copy Args((Int,Cell));

which gives a much clearer indication of what this function does(returning a list containing some?xed number of copies of a given Cell)than if we had written just:

extern int copy Args((int,int));

Of course,this looses the bene?ts of strong typing;for example,most C compilers will not report any errors for an expression like copy(val,10),despite the fact that the arguments have been written in the wrong order.One way to restore strong typing would have been to introduce new types rather than synonyms. For example:

typedef struct{int cellValue;}Cell; This might be sensible in C++,using class es in-stead of struct s,but is not suitable for some older C compilers that prohibit the use of struct values as function arguments.In truth,the ability to make puns,implicitly treating values of one type as val-ues of another,turned out to be quite convenient at several points in the code.

Another important use of the C preprocessor in the Gofer source is to support the display and handling of error messages.For example,the code:

ERROR(line)"Syntax error"

EEND;

can be used to display an error message about a syn-tax error in line line of a particular script?le and to branch to the error handler.A small collection of macro de?nitions in the?le errors.h provides ad-ditional facilities for including expressions and types in error messages.One advantage of this approach is

storage.c:Storage management(Section4)

T c T

c

T

c

T

c

T

c

input.c:

Lexical analysis and parsing (Section5)E

static.c:

Static analysis

(Section6)E

type.c:

Type checking

and translation

(Section7)

E

compiler.c:

Compilation to

supercombina-

tors

(Section8)

E

machine.c:

Execution on

an abstract ma-

chine

(Section9) Figure1:Main components of the Gofer system

that it makes it much easier to identify error messages in the source code,and helps to ensure that they are all handed in a uniform manner.

The reader may be surprised by some of the conces-sions that have been made to support older,and often obsolete,compilers and architectures.However,we have to recognize that many such systems are still in use,particularly as the personal computers on which Gofer is most widely used.

3.2Components of the Gofer system The main components in the Gofer system are illus-trated by the diagram in Figure1,which also cor-responds to the way that input programs are pro-cessed,from lexical analysis to execution on the Gofer abstract machine.Each of these components is im-plemented by a corresponding C?le,described in the following sections of the report,starting with storage.c which provides the storage management facilities used by all of the other components.

Each part of the system is responsible for initializ-ing and maintaining the variables and data structures on which it depends.This is described by includ-ing a‘control function’in each component.For ex-ample,the control function for the type checker is called typeChecker().This can be used,for exam-ple,to reset the type checker by a call of the form typeChecker(RESET).Several other messages are un-derstood by control functions,including INSTALL,to initialize local data structures,MARK,to request the component to mark local data structures in prepa-ration for garbage collection,and EXIT,to perform any?nal tidying up necessary before exiting the interpreter.The everybody()function de?ned in commonui.c can be used to send a particular message to every component of the system.For example,one of the?rst things that the interpreter does is to call everybody(INSTALL),and one of the last things it does before terminating is to call everybody(EXIT).There some other components of the Gofer system that are not included in Figure1,including:?gofer.c:The standard interpreter user inter-face.Includes code from commonui.c(parts of the user interface shared with the Gofer com-piler,gofc,for example,command line process-ing)and from machdep.c(machine dependent code,for example,terminal I/O).

?builtin.c:De?nes the built-in primitives,in-cluded from the?le prims.c.

?output.c:Provides a pretty-printer for the in-ternal representations of programs,expressions, types and kinds.These routines are mostly used to display fragments of expressions or types as part of error messages produced by the Gofer system.They have also been quite useful when debugging the interpreter itself!

We should also mention the?les gofc.c,cmachine.c and cbuiltin.c which are variants of gofer.c, machine.c and builtin.c,respectively,used in the Gofer compiler,gofc.See Section11for further de-tails.

4Storage management

One of the most important components of the Gofer system is the storage management facilities provided by storage.c and the header?le storage.h.To-gether,these de?ne many of the datatypes and struc-tures that are used in the other parts of the system. The most important data structures used in the Gofer system are as follows:

?The Text datatype,used to represent identi?er names and text strings(Section4.1).

?The Cell datatype,used as a representation for

a wide variety of values,including programs and

types(Section4.2).

?The Module datatype,used to deal with pro-grams that are built up by loading a sequence of script?les(Section4.3).

?The Gofer stack,used for a variety of purposes, including the execution of programs in the Gofer abstract machine(Section4.4).

4.1The Text datatype

Gofer programs usually contain many di?erent char-acter strings,including keywords,variable names and the text of string literals.A naive treatment of strings,allocating fresh storage for each string as it is encountered,has obvious disadvantages:

?Heap space may be wasted by keeping multiple copies of the same string,for example,a function name that is used throughout a source program.

?The memory allocators used in some C runtime systems perform poorly when burdened with the allocation of many,relatively small objects.

?Comparisons between strings are not atomic;

several character comparisons are necessary to distinguish between strings with the same initial pre?x.This is particularly important,for exam-ple,in code that searches a symbol table to?nd an entry corresponding to a particular string. Gofer avoids these problems using a table of charac-ter strings and associating each string with its o?set in this table;we use values of type Text to record these o?sets.Strings are only added to the table the ?rst time that they are encountered.Subsequent oc-currences are given the same Text value as the?rst. Using Text values to represent strings avoids all of the problems described above,and ensures that two strings are equal if,and only if,the corresponding Text values are equal.

In the current implementation,the size of the char-acter storage table is?xed at compile-time.With the limited memory of an older PC,there was little point in doing anything more sophisticated than this,par-ticularly since a dynamically allocated table would have required a further indirection to access values in the table.However,a dynamically allocated table would be useful on more powerful systems,allowing the size of the character table to be increased without a complete recompilation of the Gofer system.

Two functions are provided to convert between the String and Text types:

extern String textToStr Args((Text));

extern Text findText Args((String));The?rst of these simply returns a pointer to the string at the o?set in the table determined by the Text value.The findText function is used to?nd the Text value corresponding to a given String,ex-tending the character table if necessary.A collection of hash tables is used to speed the process of search-ing the character table for previous occurrences of a string.In the original implementation,a single hash table was used to give the starting point for a linear search through the character table.This was quickly changed,to use multiple hash tables,when we discov-ered that over80%of the time required to load large programs was spent inside the findText function, searching for previous occurrences of strings!Where possible,the current implementation now uses10lev-els of hash tables before resorting to a linear search. For large programs,this can gave an immediate?ve-fold increase in compilation speed.The bene?ts for smaller programs are less signi?cant,but still worth-while.

Two further functions:

extern Text inventText Args((Void));

extern Text inventDictText Args((Void)); are used to generate‘new’variables and dictionary parameters,respectively,in later stages of the com-piler.They are implemented as functions that return values outside the range of o?sets into the character table.

4.2The Cell datatype

One of the advantages of programming in a language like Gofer is the use of automatic storage allocation and garbage collection.This frees the programmer from the need to specify when memory allocation is required,or when allocated sections of memory can be released for use in other parts of the program.Ex-plicit memory management of this kind is a notorious source of errors in languages like C.

To support automatic storage management,the Gofer system includes an implementation of a garbage-collected heap with values of type Cell used as‘point-ers’to objects in the heap.This turns out to be a very useful data structure and is used throughout the sys-tem,not just for the execution of Gofer programs. For example,the Gofer heap is also used to build parse trees for input programs,to store types for use in the type checker,and to implement the translation of functions to supercombinators.

In the following subsections we outline both the in-terpretation and implementation of Cell values.Be warned that any reasonably complete description of

Cell values is likely to be long and complicated.For a?rst reading,it may be best to simply scan the following sections,without attempting to absorb too many of the details.

4.2.1Interpretation of Cell values

The Cell datatype includes representations for many di?erent kinds of value.The following list describes some of the most important kinds of Cell value:?Primitive constants:The Cell datatype in-cludes representations for several di?erent kinds of constant values,including integers(corre-sponding to the int type in the underlying C implementation),?oating point numbers,char-acters and string literals.

?Pairs:Used to construct compound values,in-cluding pairs,trees and lists.A pair containing two given Cell values,x and y,can be obtained as the result of the function call pair(x,y).

Conversely,the two components of a pair p can be extracted using the expressions fst(p)and snd(p).

Pair cells are also used to represent function application in both the compile-time and run-time representation of Gofer programs.The storage.h header?le includes the following macro de?nitions to support this use:

#define ap(f,x)pair(f,x)

#define fun(c)fst(c)

#define arg(c)snd(c)

Pairs are also used to build a representation for lists;storage.h contains the following macro de?nitions to describe the encoding of lists: #define cons(x,xs)pair(x,xs)

#define hd(xs)fst(xs)

#define tl(xs)snd(xs)

#define singleton(x)cons(x,NIL)

#define isNull(x)((x)==NIL) In words,a non-empty list is represented by a pair whose fst component stores the head of the list,with the tail of the list(i.e.the remaining elements)in the snd component.The special cell value NIL is used to represent the empty list(and in other parts of the implementation as a general purpose‘dummy’value).We refer to lists con-structed in this manner as being‘internal’lists;

values corresponding to the list datatype used by

the Gofer program have a very di?erent represen-tation.For example,the fully evaluated Gofer list[1..3]is represented by:

ap(ap(nameCons,mkInt(1)),

ap(ap(nameCons,mkInt(2)),

ap(ap(nameCons,mkInt(3)),

nameNil)))

where nameCons and nameNil are constant val-ues(see the description of name values below) corresponding to the Gofer constructor functions (:)and[],respectively.

Using three di?erent names,for example,pair, ap and cons,for a single function may seem an unnecessary complication.However,in prac-tice,careful use of these di?erent names actually makes the code a little more readable.?Variable names:There are several di?erent kinds of variable names that can be represented as Cell values,including ordinary variables,con-structor variables and dictionary variables.In each case,the expression textOf(v)gives the Text name for the variable represented by a Cell value v.

?Constructor cells:The Cell datatype includes representations for fragments of parse trees.For example,a list comprehension generator of the form p<-exp is represented by a FROMQUAL cell that contains a pair whose components are the pattern p and the expression exp.In later sec-tions,particularly in grammars describing inter-nal representations of Gofer programs,we will use the notation FROMQUAL(p,exp)to describe a Cell value that is constructed in this way.?Special cell values:The Cell datatype in-cludes a number of special values for certain con-stants.Examples of this include:

–ARROW,LIST and UNIT,used to represent the function space(->),list[]and unit

()type constructors,respectively.UNIT is

also used as the representation for the Gofer

value(),the only value(other than⊥)of

type().

–WILDCARD,representing the wildcard pat-tern_.

–STAR,representing the kind of all types,an important concept in the treatment of con-

structor classes[33].Function kinds,map-

ping constructors of kind k1to constructors

of kind k2,are represented by pair(k1,k2).

?Tuples:Used in the representation of tuple types and values.For example,mkTuple(2)is used in the construction of pairs.The Cell datatype actually includes values corresponding to nullary and unary tuples,mkTuple(0)and mkTuple(1),respectively,but they are not used in the current implementation.

?O?sets:Used as place holders for type variables in a polymorphic type,or for bound variables in a supercombinator de?nition.See Sections7and8 for more details.

?Dictionaries and selectors:Dictionaries are used to package groups of related values as a sin-gle unit.Selectors are used to extract the compo-nents of a dictionary.This is described in more detail in Section7.5.

?Type constructors:Used to represent Gofer type constructors introduced by type or data declarations,or as primitive built-in datatypes such as Bool,Int and Char.The details about the type constructor represented by a Cell value tc are recorded in the C structure tycon(tc). For example:

–tycon(tc).text gives the name of tc as a Text value.

–tycon(tc).kind gives the kind of tc,as described in[33].

–tycon(tc).what contains a code indicating whether the type constructor was de?ned

by a data de?nition(DATATYPE),a type

synonym(SYNONYM),or a restricted type

synonym(RESTRICTSYN).

–tycon(tc).defn contains the expansion of

a type synonym or the list of constructor

functions for an algebraic datatype.

Note that tycon()is a macro,not a function returning a struct as the syntax might suggest.?Names:Used to represent named values that are needed for the execution of Gofer programs. This includes user-de?ned values,constructor functions,member functions,primitives and new supercombinators introduced by the compiler. Like type constructors,the details corresponding to a Cell value n representing a name are held in a C structure name(n),including the?elds:–name(n).text:the Text name of n.

–name(n).arity:the number of arguments that the function expects.An arity of zero

indicates a constant applicative form(CAF)

as described in[48].

–name(n).type:the type of n,if known.

–name(n).defn:used to distinguish di?er-ent kinds of name.The value of this?eld

may indicate a constructor function CFUN or

a member function MFUN.For user-de?ned

functions,this?eld is also used to record de-

pendency information during compilation.

It is also used to save the result of the?rst

(and thereafter,only)evaluation of a CAF

in machine.c.

–name(n).code:the starting address for the code used to implement a supercombinator.

See Section9for more details.

–name(n).primDef:a pointer the implemen-tation of a primitive function(or zero,if the

name does not correspond to a primitive).

As in the case of type constructors,name()is a macro,not a function returning a struct.

?Type classes:Used to represent individual type (or constructor)classes.Once again,if c is a Cell value representing a class then there is a structure class(c)that includes?elds:

–class(c).text:the Text name of c.

–class(c).arity:the number of arguments that the class takes.

–class(c).sig:the kind of constructor ex-pected for each parameter.

–class(c).supers:the list of superclass constraints.

–class(c).members:the list of member functions for c.

–class(c).defaults:the list of default def-initions for each member function(if any).

–class(c).instances:the list of instance declarations for class c.

–class(c).dictIndex:a pointer to the in-dex of dictionary values for the class.

The use of these values is described in more detail in Section7.5.

?Type class instances:Like type constructors and names,the details about the instances of a type class are kept in structures indexed by Cell values.For example,if in is the Cell value corresponding to the instance declaration

Value whatIs code predicate selector constructor(s) Integers INTCELL isInt intOf mkInt

Floating point FLOATCELL isFloat floatOf mkFloat Characters CHARCELL isChar charOf mkChar

Pairs AP isPair fst,snd pair

Tuples TUPLE isTuple tupleOf mkTuple

O?sets OFFSET isOffset offsetOf mkOffset Selectors SELECT isSelect selectOf mkSelect Dictionaries DICTCELL—dictOf mkDict

Type constructors TYCON isTycon tycon mkTycon,newTycon Names NAME isName name mkName,newName Type classes CLASS isClass class mkClass,newClass Class instances INSTANCE isInst inst mkInst,newInst Figure2:Predicates,selectors and constructors for Cell values

instance(Eq a)=>Eq[a]where

[]==[]=True

...

then the structure inst(in)includes?elds:

–inst(in).cl:The class that the instance applies to;in this case,Eq.

–inst(in).head:The form of instance spec-i?ed;in this case,Eq[a].

–inst(in).specifics:The context part of the declaration;in this case,a singleton list

containing the class constraint Eq a.

–inst(in).implements:The list of mem-ber function implementations;in this case,

a singleton containing the name of the func-

tion implementing equality of lists.

Once again,the use of these values is described in more detail in Section7.5.

Use of these di?erent kinds of Cell values is sup-ported by a small collection of utility functions,many of which are summarized in Figure2,including:?Predicates,to determine if a given Cell repre-sents a particular kind of value.

?Selectors,to return the value associated corre-sponding to a particular kind of Cell.The fst, snd and name functions described above are all examples of this.

?Constructors,to obtain Cell values correspond-ing to particular kinds of value.The pair func-tion described above is a simple example of this.The whatIs function provides another way to deter-mine what kind of value is represented by a given Cell.Figure2lists some of the codes returned by whatIs for frequently used Cell values;for example, a test of the form whatIs(c)==NAME is equivalent to isName(c),although the latter may be a little more e?cient.The whatIs function is more useful as a means of testing for particular types of Cell that do not have a prede?ned predicate.For example,test-ing the condition whatIs(c)==DICTCELL is the easiest way to determine whether c represents a dictionary value.Another important application of whatIs is to provide a simple form of pattern matching;the fol-lowing idiom is widely used in the implementation of Gofer,reducing the need for repeated inspection of Cell values:

switch(whatIs(e)){

case NAME:...

case CHARCELL:...

...

default:...

}

Pro?ling experiments suggest that whatIs is one of the most frequently executed functions in the whole Gofer system,so it is certainly worth investing a little time to try and make it as e?cient as possible.

4.2.2Implementation of Cell values

Starting from the description of Cell values above, the most obvious implementation would be to use an algebraic data type,similar to those that a Gofer pro-grammer would normally introduce using a data def-inition.

'

¢¢¢

¢E

pairs

NIL tags

BCSTAG specials TUPMIN tuples

OFFMIN o?sets classes

CHARMIN chars

INTMIN integers

INTMAX

Figure 3:Implementation of Cell values as ranges of integers (not to scale).

In fact,the current implementation uses a rather more complicated scheme,encoding arbitrary Cell values as integers.The main idea is to use di?erent ranges of integers to represent di?erent kinds of value.Figure 3illustrates part of the encoding used in the current implementation.This approach has some im-portant bene?ts over the more direct implementation:?It avoids the use of pointers in the representation of Cell values.This was an important consid-eration for the PC implementation which would have required 32bit pointers and,as a result,doubled the storage requirements of a system us-ing 16bit integers.

?Occurrences of commonly used values,including names,type constructors and small integers,do not require any storage,regardless of the number of times that they are used during the compila-tion or execution of a program.

At the same time,this representation also has some signi?cant disadvantages:

?The task of decoding Cell values can be a little expensive.The use of integers instead of point-ers also carries some performance overheads,for much the same reason that an array access through a single pointer indirection is usually more e?cient than using an integer index which involves additional,implicit pointer arithmetic.?It is very di?cult to change the mapping between integer ranges and di?erent kinds of Cell value while the system is running.This might be im-portant if we wanted to be able to modify the initial con?guration,for example,to accommo-date larger input programs.The integer ranges used in the current implementa-tion,and the values that they correspond to,are as described below.A long string of #define directives in the header ?le storage.h is used to ensure that none of these ranges overlap.

?Negative integers are used exclusively to repre-sent pair values.This allows us to implement

the test isPair(c)to determine if c represents a pair,as a comparison c<0that is very cheap on most machines.In theory,this limits the maxi-mum number of pair cells in the heap to be equal to the number of negative integers (i.e.2b ?1pairs where b is the number of bits in an inte-ger).However,in practice,this doesn’t cause any problems:Working with a 32bit machine,the upper bound is much larger than any heap size that we are ever likely to use.On a 16bit PC,the upper bound on heap size is much lower (a maximum of 32,768pairs)but the PC archi-tecture doesn’t have enough memory to support a larger heap.

The ?rst and second components of each pair are stored in two arrays of Cell s called heapFst and heapSnd each of which contains heapSize elements.The use of two arrays rather than a single array containing both components of each pair was another concession to the PC architec-ture which limits the maximum size of an array (at least,if we hope to avoid expensive index cal-culations)to 64K.By using two arrays,the PC architecture can support a 128K heap contain-ing the maximum of 32,768pairs,each requiring 4bytes.However,the decision to use two arrays may seem rather shortsighted because it makes the allocation of variable size heap objects much more di?cult;this might be an obstacle to ef-?cient implementation of arrays or records.In fact,as we describe in the next section,the con-straints imposed by the garbage collector in the current design would still have made it almost impossible to support variable length allocation.Because pairs are represented by negative Cell values,we use two variables heapTopFst and heapTopSnd to point to the locations im-mediately above the two arrays (i.e.to heapFst+heapSize and heapSnd+heapSize ,re-spectively).The fst and snd selectors are im-plemented by macros:#define fst(c)heapTopFst[c]#define snd(c)

heapTopSnd[c]

so that the negative index values for c?nd their way back to the appropriate elements in the ar-ray.Since the Gofer heap is quite heavily used, it would probably be useful to store the variables heapTopFst and heapTopSnd in global registers. The default heap size setting for a particular ma-chine can be changed using a command line op-tion,but the current implementation does not make any provision for expanding the heap while the interpreter is running.This might be useful, for example,to allow the user to request an in-crease in heap size,or even to permit automatic heap expansion if garbage collection fails to re-claim su?cient space.There is no reason why this feature could not be added but this would only be of use on larger systems;the default heap size settings for older PCs are already set to the maximum possible values.

?The zero value is used to represent the NIL value, making tests for the empty list very fast.

?INDIRECT and INDIRECT1,symbolic names for the integers1and2,are used in the implemen-tation of indirection nodes.See Section9.1for more details.

?Values in the range[1..BCSTAG-1]are used as tags in the fst component of a pair represent-ing a‘boxed’value.The following table lists the boxed values used in the current implemen-tation.The right hand column gives the type of value that is stored in the snd component of these boxed values:

VARIDCELL Identi?er variable Text

VAROPCELL Operator variable Text

DICTVAR Dictionary variable Text

CONIDCELL Identi?er constructor Text

CONOPCELL Operator constructor Text

STRCELL String literal Text

INTCELL Integer literal Int

ADDPAT(v+k)pattern Int

MULPAT(c*v)pattern Int

DICTCELL Dictionary Dict

FILECELL Input?le no.Int

FLOATCELL Floating pt Float One of the main purposes of a tag value is to indicate that the snd component of a pair should be ignored by the garbage collector.

?Values in the range[BCSTAG..SPECMIN-1]are used as tags in boxed values whose snd compo-nent is another Cell.The FROMQUAL value is a simple example of this with a pair containing the

pattern and expression for a generator as its snd component.

?Values in the range[SPECMIN..TUPMIN-1]are used for special cell values such as UNIT, WILDCARD and STAR.

?The?rst NUM TUPLES values in[TUPMIN..]are used to represent tuple type and value con-structors.The default setting of NUM TUPLES in prelude.h allows for tuples with up to100com-ponents.In practice,it is very rare to?nd Gofer programs that use tuples with more than6com-ponents.

?The?rst NUM OFFSETS values in[OFFMIN..]are used to represent o?sets.The default setting of NUM OFFSETS to1024in prelude.h allows for ex-tensive use of pattern matching and local vari-ables in function de?nitions,and for up to1024 di?erent polymorphic type variables in inferred types.Examples exceeding this limit are only usually of interest as pathological examples.

?The?rst NUM TYCON values in[TYCMIN..]are used to represent type constructors.The tycon selector is implemented using the macro:

#define tycon(tc)tabTycon[(tc)-TYCMIN] where tabTycon is an array with NUM TYCON structures containing the?elds described in the previous section.

?The?rst NUM NAME values in[NAMEMIN..]are used to represent names.The name selector is im-plemented using an array of structures in a sim-ilar way to the tycon selector described above.

?The?rst NUM SELECTS values in[SELMIN..] represent dictionary selectors.

?The?rst NUM INSTS values in[INSTMIN..]cor-respond to instances of a type class.The inst selector is implemented by using Cell values to index the elements in an array of structures.?The?rst NUM CLASSES values in[CLASSMIN..] are used to represent classes,with the class se-lector implemented in similar way to tycon,name and inst.

?The?rst NUM CHARS values in[CHARMIN..]are used to represent character values.The default value of NUM CHARS allows for256characters, enough to support the full character set of most current machines.

?The remaining values not covered by the above, all in the range[INTMIN..INTMAX]are used to represent‘small’integers as unboxed values.In practice,the INTMIN value used here tends to be quite small,while INTMAX is the largest positive integer value.As a result,the range of small in-tegers is actually quite large,not much less than the range of integers that can be represented us-ing b?1bits,assuming b bits in every Cell value.The midpoint of this range is used as a representation for zero:

#define INTZERO(INTMIN/2+INTMAX/2)

This makes it possible to encode many integer values as Cell s without requiring any additional storage.Integer values that cannot be repre-sented in this way must be stored as boxed val-ues,i.e.as a pair with?rst component INTCELL and a second component containing the integer.

Since many programs use only small integer val-ues,this representation gives a noticeable reduc-tion in the amount of space used by programs.

On the other hand,simple arithmetic operations on integers are more expensive to implement be-cause they have to be written to deal with both boxed and unboxed integer values.In an inter-preter like Gofer there are many more signi?cant performance overheads to worry about.How-ever,this representation would not be suitable for other systems where execution speed is an issue.

4.2.3Garbage collection

We have already described how new pair cells are al-located by calling the pair()function.But what happens when all of the heapSize pairs in the heap have been allocated?Like many other systems,Gofer relies on the assumption that,by the time this hap-pens,many of the pairs allocated earlier in the com-putation will no longer be required.A garbage col-lector is used to determine which parts of the heap can be reused,linking them together as a list of free pairs called the freeList.New pair cells can then be allocated by removing an element from the free list.When the free list becomes empty,the garbage collector is called once again,to build a new free list, and the allocator continues as before.Although it is possible for the heap to become full,most of the time,the garbage collector helps to maintain the il-lusion that there is no limit on the number of pairs that can be allocated.Automatic garbage collection is particularly conve-nient because it frees the programmer from the re-sponsibility of deciding when a particular piece of storage can safely be reused,and avoids hard to lo-cate errors that can occur when a programmer makes the wrong decision.Indeed,it has even been argued that the use of garbage collection can be faster than other forms of memory allocation[2],although we would not attempt to make any such claims for the particular garbage collection system used in Gofer. Although there is no need for the programmer to specify when a particular section of storage should be reused,it is important to ensure that the garbage collector will be able to identify all of the parts of the heap that are still in use.This is achieved by listing a collection of roots,i.e.pointers to data structures in the heap that must be preserved by the garbage collector.Roots come from several di?erent sources. For example,the type and defn?elds in the struc-ture describing a Name value,local variables used to hold intermediate results,and global variables point-ing to list of de?nitions in a particular input pro-gram,must all be preserved by the garbage collec-tor.If they are not,the program will behave badly when the parts of the heap that these variables point to are overwritten with new values.Each compo-nent of the system includes a control function(see Section3.2)that responds to the MARK message by marking all of the roots relevant to that part of the system.The garbage collector uses this by calling everybody(MARK).Any part of the heap that is not marked will be reused.For example,it is important to realize that,if a component is modi?ed to use a new global variable,newList,pointing to a list of values in the heap,then the control function for that component must be modi?ed to include the line: mark(newList);

It is also sensible to ensure that newList is initial-ized and reset to a suitable value(usually NIL)in response to the INSTALL and RESET messages,respec-tively.Failure to do this may mean that the storage pointed to by newList is retained for longer than it is actually required.

Everything that we have described so far is relatively straightforward.We have hinted at some speci?cs of the algorithm used to allocate new pairs,and to collect unused cells using the freeList;this is an example of a mark-scan garbage collector.However, compared with the garbage collection algorithms used in other systems,our mark-scan collector has some serious disadvantages:

?The time taken to build the new freeList after

all the cells have been marked is proportional to the total size of the heap,not to the size of the heap that is actually in use,which is often much smaller.

?Allocating new pairs from a free list(including

a test to make sure that the list is non-empty)

is expensive,compared with alternative schemes where new pairs are allocated from a contigu-ous array of cells,with a heap pointer that iden-ti?es the next free heap location.Testing for heap over?ow requires a comparison of the heap pointer with a pointer to the end of the heap.

In addition,it is often possible to allocate sev-eral new pairs at a time,using only a single heap over?ow test.

?An additional bene?t of the approach described above is that it allows the allocation of di?erent sized heap objects.For example,to allocate an array of100cells,we simply need to increment the heap pointer by100,checking?rst for over-?ow of course.In theory,a mark-scan collector could also be used to allocate variable sized heap objects.However,in practice,this often fails because the free space may become fragmented, making it ine?cient,and sometimes impossible, to allocate a block of memory of the right size, even when the total amount of free memory is large enough.

These problems can be avoided by using a garbage collector that is allowed to move objects during garbage collection,typically using a compaction al-gorithm,that avoids any heap fragmentation.For this to work correctly,we need to to ensure that the garbage collector will update any pointers to the old position of an object to re?ect its new position. Unfortunately,it is not possible to ensure this prop-erty for the Gofer garbage collector;to allow the heap to be used in arbitrary C functions in the system,the garbage collector also uses the C calling stack as a source of roots.To see why this is useful,consider the following function,taken from storage.c,which can be used to allocate a list containing a given num-ber of copies of a particular Cell value:

List copy(n,x)

Int n;

Cell x;{

List xs=NIL;

while(0

xs=cons(x,xs);

return xs;

}Suppose now that a garbage collection occurs part way through this routine,for example,when only half of the required list has been constructed.Clearly,it is important to ensure that the current value of xs is preserved by the garbage collector.Similarly,the value of the x parameter may need to preserved by the garbage collector;in this particular case,this is only necessary if the garbage collector is invoked on the?rst call to the cons function—after that,the value pointed to by x would have been included,and hence marked,as part of the data structure pointed to by xs.The easiest way for the garbage collec-tor to?nd these values is to look for them on the C calling stack.Of course,the C stack also contains several other kinds of values including,for example, other function parameters like n,temporary values and function return addresses.When the garbage collector encounters a value on the C stack that looks like a reference to a part of the heap4,it must treat that value as a root for the garbage collector.On the other hand,it should not attempt to change the value on the stack,allowing for the possibility that it might actually be some other kind of value which just happens to fall in the same range as a heap reference. For example,modifying a return address is likely to cause the program to branch to the wrong location at some later stage,with unpredictable,and possibly disastrous e?ects.

In this particular example,it would have been possi-ble to change the de?nition of copy()to ensure that there were enough free cells available before attempt-ing to construct the result list,avoiding the chance of a garbage collection during the construction of the re-sult list.This is not a general solution;in some cases, it is impossible,or at best,very expensive,to calcu-late an upper bound on the amount of storage that a particular C function will allocate.Furthermore,it requires the programmer to take more responsibility5 for storage allocation,complicating the code that has to be written.

There are other alternatives,using extra code in the de?nition of C functions,for example,to label inter-mediate values,to avoid the need for garbage collec-tion o?the C stack.However,with many of these schemes,we soon?nd ourselves writing the C equiv-alent of G-code,a low-level assembly language(see Section9.2)to ensure proper marking of roots.This 4The predicate isGenPair()is used as a more accurate al-ternative to isPair()to test for genuine pair cell values,i.e. excluding any Cell values less than-heapSize.

5It’s not that we don’t trust the programmer(in this case, one and the same person!);we simply recognize that it is all too easy to make errors in memory allocation,and often very di?cult to detect and correct such mistakes.

would not be so bad if the copy()function was one of the most complex functions that we had to deal with;unfortunately,it is one of the very simplest. As if the limitations of the garbage collector that we have already discussed are not enough,there are some further problems that we should mention.

?First,the garbage collector is conservative,in the sense that it may preserve parts of the heap that are not actually needed[59,9].This happens when the garbage collector misinterprets a value on the C stack as a pointer into the heap.In some situations,this causes a space-leak,pre-serving large data structures long beyond the point where they are actually needed.Fortu-nately,this does not seem to cause too many problems in practice,except on some occasions when the heap is already almost full to capacity.?Another major problem that we have skimmed over until now is that accessing values from the

C stack is inherently unportable,and generally

speaking,very poor C programming practice.

The standard version of the garbage collector relies on the assumption that the C stack can be treated as a contiguous array of equally sized Cell values.This is true for many systems,from small PCs to powerful workstations,but there are also some examples for which these assump-tions are not valid.For example,in a port of the Gofer system to run under Acorn’s RISCOS op-erating system,Bryan Scattergood had to mod-ify the garbage collector to deal with a stack implemented by a linked list of frames.As an-other example,in the development of MacGofer, Kevin Hammond had to modify other parts of the system to accommodate the use of an80-bit (10byte)representation for?oating point values that does not?t directly into the4byte units used for Cell values.As another illustration of the kind of portability problems that we have run into,it is common for optimizing C com-pilers to place temporary values in registers.In some cases,and despite our e?orts to avoid the problem,the values in registers are hidden from the garbage collector,even when they should be treated as roots.For example,on a Sun worksta-tion,the compiler.c part of the Gofer system, which makes heavy use of the garbage collected heap,is usually compiled without optimization to avoid exactly this kind of problem.

In conclusion,the garbage collection system is an enormous pain,and a signi?cant source of portability problems.More than any other part of the system,it demonstrates some of the compromises that have been necessary in the development of Gofer.Hap-pily,in practice,the garbage collector is usually very reliable.For example,we have run large Gofer pro-grams taking several days to execute and requiring several tens of thousands of garbage collections with-out any apparent problems.In light of the discussion above,we consider ourselves very fortunate that the garbage collector works as well as it does!The cur-rent implementation allows us almost transparent use of the heap in C function de?nitions.Without this, we believe that it would have been signi?cantly more di?cult to write and maintain large sections of the system,particularly the supercombinator compiler in compiler.c.At the same time,the garbage collector does still cause some problems,in particular,pro-hibiting useful extensions such as the allocation of variable sized blocks of memory.Perhaps these prob-lems can be avoided in future versions of the system by switching to a language that includes built-in sup-port for garbage collection.Alternatively,it might be possible to use a language,for example C++,allow-ing special treatment of Cell values to ensure proper garbage collection;it remains to see what kind of per-formance overheads this approach might carry.

4.3The Module datatype

As we have already described in Section2,the Gofer system allows the user to load a sequence of script ?les,each layered on top of the de?nitions in pre-viously loaded?les.Apart from Cell values which have been described in detail in the previous section, most other values,for example,Name s,Class es and Inst s,are allocated from?xed tables with‘high wa-ter mark’values,for example,nameHw,classHw,and instHw,respectively,pointing to the next free posi-tion in each table.

The Module datatype is used to record the number of script?les that have currently been loaded.More importantly,for each script?le loaded,the system maintains a table recording the values of the various high water mark variables immediately before each ?le was loaded.These values are saved by a call to the function:

Module startNewModule Args((Void));

which returns a module number for the new script?le. Later,the system can restore the storage allocation to its position immediately before this module was loaded by a call to the function:

Void dropModulesFrom Args((Module));

In addition to resetting the values of the various high water marks,this function also requires some small adjustments to some additional data struc-tures,such as the hash table used to locate Name values.Together,these functions provide a simple checkpointing mechanism.For example,by calling startNewModule()before reading a new script?le, or before reading an expression to be evaluated,it is easy to restore the original state if an error occurs,or once the expression has been evaluated,respectively.

A more sophisticated scheme for the allocation and recovery of values from tables would be necessary if the system did not assume a strict dependency be-tween the script?les in the order that they are loaded.

4.4The Gofer stack

Several parts of the Gofer system make use of a stack of Cell values:

?The parser uses a stack to record intermediate values corresponding to fragments of input pro-grams(Section5.3).

?The algorithm for calculating strongly connected components of a program dependency graph dur-ing static analysis uses a stack to record nodes in the graph that have already been visited(Sec-tion6.2).

?The Gofer abstract machine uses a stack to hold intermediate values and function arguments dur-ing program execution(Section9).

All of these applications are implemented using the same stack data structure,with the most important operators as follows:

Void clearStack Args((Void));

Void push Args((Cell));

Cell pop Args((Void));

Cell top Args((Void));

Cell pushed Args((Int));

The use of these functions should be obvious from their names and types,except perhaps the last; pushed(n)returns the value n positions from the top of the stack.The expression top()is equivalent to pushed(0).In fact,these operators are implemented by preprocessor macros rather than function calls. Note that all of the values on the stack are treated as roots for the garbage collector;this is important to ensure that the stack is preserved if a garbage collec-tion occurs during parsing,static analysis or program execution.5Lexical analysis and parsing The input.c program is used to read and parse both the de?nitions in Gofer scripts and the com-mands and expressions that are entered into the https://www.wendangku.net/doc/e411768419.html,bining a hand-written lexical analyzer and a yacc generated parser[19],this part of the sys-tem draws on standard techniques of compiler con-struction.

5.1Lexical analysis

Most of the code for lexical analysis is included in the ?le input.c.A two character lookahead,represented by the two variables c0and c1is su?cient to iden-tify all of the tokens used by the Gofer system.At each stage,the current position in the input text is maintained in the row and column variables.Column positions are used chie?y to keep track of indentation which is signi?cant in the implementation of the lay-out rule.Row values,corresponding to line numbers in Gofer programs,are recorded at various points in the parsed form of input expressions so that errors detected at later stages in the system can be referred back to the appropriate point in the source code. The lexical analyzer can be initialized to take its in-put from the console,a project?le or a Gofer script ?le using one of the three functions:

Void consoleInput Args((String));

Void projInput Args((String));

Void fileInput Args((String,Long)); For console input,the String argument is used as the Gofer prompt.In the remaining two cases,the String argument is the name of the?le to be read. The second argument to fileInput gives the length of the input?le(if known)and is used to determine the portion of the?le that has been read at any point during parsing.

The lexical analyzer is able to read Gofer script?les using both the standard and literate styles.In the latter case,program lines in input?les must begin with a‘>’character in the?rst column;all other lines are treated as comments.This convention,described more fully in[16,Appendix c],is widely used because it allows program text to be freely mixed with its documentation.The ability to read literate scripts directly without preprocessing does not signi?cantly increase the complexity of the lexical analyzer.

For each token encountered,the lexical analyzer re-turns a code to the parser to indicate what kind of to-ken has been read.For example,NUMLIT for numeric literals,VARID for a variable name and COCO for a::

symbol.Distinguishing between di?erent types of to-ken is all that the parser needs to process the input, but many of these di?erent kinds of tokens have cor-responding attributes that are needed in later stages; obvious examples include the value of a numeric lit-eral or the name of a variable,both of which can be represented as Cell s.These additional properties are passed to the parser in the variable yylval,the standard convention for yacc-generated parsers.In some cases,notably for the=and::symbols,the value returned in yylval is the line number on which the symbol occurs.These line numbers are used in later stages of the system to locate the(approximate) source of an error.

5.2The Gofer grammar

The grammar for Gofer programs and expressions is de?ned by the?le parser.y,used as input to yacc to produce parser.c which is#include d as part of input.c.For convenience,the grammar includes pro-ductions for the module headers,including import and export declarations,that are used in full Haskell programs.This means that it is often possible to use a ?le containing one or more Haskell module de?nitions as input to Gofer without modi?cation.However, other than checking for syntax errors,these module headers are completely ignored.

The Gofer grammar is closely based on the de?ni-tion of Haskell,although it is a little more liberal in some respects.As a simple example,patterns in Gofer programs are actually parsed as expressions. This helps to avoid unnecessary con?icts and ambi-guities in the https://www.wendangku.net/doc/e411768419.html,ter,in static.c,static checks are used to ensure that the expressions parsed are valid patterns.A similar technique is used to parse certain forms of type expression.The following examples show that several tokens of lookahead may sometimes be necessary to determine whether a given type expression includes a(type class)context: T a->T b vs.C a=>T a

(T a,T b)vs.(C a,C b)=>a->b. Since yacc grammars only allow a single lookahead token,we deal with this problem by parsing the con-text part of a type expression as if it were just a type. Later,if a=>symbol is detected,we use a simple static check to ensure that the value parsed as a type can instead be treated as a context.For example,the expression Int=>Bool would be accepted by the parser,but rejected by the static check.On the other hand,the current grammar will accept a type ex-pression of the form((Eq a))=>a->Bool,even though a strict adherence to the Haskell grammar would prohibit the repeated parentheses around the predicate Eq a.

There are also some small di?erences in the interpre-tation of certain expressions.For example,in Haskell, the two expressions:

let(n+1)=43in n

let n+1=43in n

have di?erent meanings;the?rst evaluates to42 while the local de?nition in the second introduces a new value for the(+)operator,not for n,and hence returns whatever value was bound to n in the enclos-ing environment(or a compile-time error if no such binding exists).In Gofer,the second interpretation is used for both expressions;(n+k)patterns cannot be used at the top-level of a pattern binding,with or without the parentheses.

Another interesting aspect of the Gofer parser is the way that expressions involving in?x operators are treated.The Haskell grammar[16,Appendix B]de-?nes the syntax for in?x operators using a complex family of productions indexed by precedence and?x-ity values.Implementing this directly as a yacc gram-mar would cause a signi?cant increase in the size of the grammar.Instead,the Gofer parser reads ex-pressions involving in?x operators as a sequence of expressions,separated by operator symbols,without any further processing.When the whole sequence has been read,it is passed as an argument to the tidyInfix function at the end of parser.y that uses a simple shift-reduce parser to determine the correct interpretation of the expression.In a system sup-porting Haskell-style import declarations,this tidy-ing process could pro?tably be delayed until the inter-face?les for imported modules have been read,pro-viding the?xities for imported in?x operators.Apart from simplifying the yacc grammar,this approach would also make it very easy to extend the range of precedence values that can be assigned to in?x oper-ators.Following Haskell,the current implementation allows only single digit precedences.

Another small di?erence between the Haskell and Gofer grammars is in the treatment of the pre?x unary minus operator.The de?nition of Haskell,re-quires unary minus to be treated as having a prece-dence value of6,the same precedence used for bi-nary addition and subtraction.In Gofer,unary minus binds more tightly than any in?x operator,but less tightly than function application.This rarely causes any di?culties in practice,although we will proba-bly change the Gofer grammar at some point in the future to be consistent with Haskell.

5.3The shadow stack

During parsing,the Gofer system is constantly using the heap to build expression trees corresponding to parsed fragments of the source program.It is impor-tant to ensure that all of these intermediate values are preserved if a garbage collection occurs during parsing.In fact,parsers generated by yacc already maintain a stack of such values for internal use;if we could make the values on the yacc stack known to the garbage collector,then we wouldn’t have to worry about loosing the parse trees for intermediate fragments during garbage collections. Unfortunately,because the yacc stack is intended only for internal use,there is no o?cially documented way to access these values.Instead,using some in-sight into the way that yacc generated parsers work, the current implementation uses the Gofer stack to simulate the state of the internal parser stack.This duplication of e?ort has obvious disadvantages,but does at least ensure that the garbage collector will preserve intermediate values during parsing in a rel-atively portable manner.

We refer to this process as shadowing the yacc stack. The?rst step in the shadowing process is to ensure that the lexical analyzer pushes the appropriate value onto the Gofer stack every time it encounters a to-ken in the input?le.Most of the remaining work is taken care of by the gcShadow()function de?ned in parser.y.This is used in productions such as:

ctype:ctype atype{$$=gc2(ap($1,$2));}

An expression of the form gc2(e)is just an abbrevi-ation for gcShadow(2,e),the purpose of which is to remove the top two elements of the stack and replace them with the new expression e.In fact,the de?-nition of gcShadow is a little more complicated since we need to take account of situations where the stack already contains an extra lookahead token.We refer the reader to parser.y for more details.

5.4Implementing the layout rule

The Haskell layout rule,also adopted by Gofer,al-lows a programmer to use layout and indentation to re?ect the structure of a program in a concise and natural manner.In e?ect,the layout rule works by automatically inserting{,;and}tokens at certain points in the input stream.For example,the case expression:

case expr of True->branch1

False->branch2is transformed,by the insertion of these additional tokens,to:

case expr of{True->branch1;

False->branch2

}

We refer the reader to[24,Chapter13]and[16,Sec-tion1.5]for a more complete description of the layout rule and its use.

The implementation of the layout rule is a little tricky and relies quite heavily on the error recovery features of yacc and on some mildly complicated interactions between the lexer and parser.The details are a little too technical for this report and we refer the reader to the code for input.c and parser.y,in particu-lar,the productions for close and close1,for more information.

5.5Abstract syntax for parsed values To explain the role of the di?erent components in the Gofer system,we will describe the internal rep-resentation of Gofer programs at each stage using a sequence of simple grammars.The purpose of the lexical analyzer and parser is to translate input pro-grams in the concrete syntax of Gofer into the?rst of these abstract syntaxes.

The main result of parsing a Gofer program is a list of equations mixed with type signature declarations. Using the grammar in Figure4,this can be described as a list of the form[Eqn].Note that,following the Gofer syntax for lists,we use the notation[...]to in-dicate a list of values,not an optional item as in some BNF-style notations.The Line type used here indi-cates an integer value corresponding to a line number in the source program.We have used the names VAR and CON to indicate variables and constructor identi-?ers respectively.In fact,the parser and lexer actu-ally go a step further,making a distinction between the case when an identi?er is written with applica-tive/pre?x syntax(VARID/CONID)and the case when in?x syntax is used(VAROP/CONOP).

There are two useful observations to make about this grammar.First,as suggested in earlier com-ments,the grammar does not distinguish between expressions and patterns;for example,the fact that WILDCARD is not permitted in an expression or that LETREC clauses cannot appear in patterns is not cap-tured by the grammar.These errors will not be detected until later,during the static analysis in static.c(Section6).Second,the grammar is quite complex;while it omits much that is purely syntactic such as comments and parentheses used for grouping,

Eqn::=SIGDECL(Line,[Var],SigType)

|(Expr,Rhs)

Expr::=VAR Text

|CON Text

|AP(Expr,Expr)

|Const

|COND(Expr,Expr,Expr)

|FINLIST[Expr]

|LETREC([Eqn],Expr)

|LAMBDA Alt

|COMP Comp

|RUNST Expr

|ESIGN(Expr,SigType)

|CASE(Expr,[(Pat,Rhs)])

|ASPAT(Var,Pat)

|LAZYPAT Pat

|WILDCARD

Const::=UNIT

|TUPLE Int

|STRCELL Text

|CHARCELL Char

|FLOATCELL Float

|INTCELL Int

Comp::=(Expr,[Qual])

Qual::=FROMQUAL(Pat,Expr)

|QWHERE[Eqn]

|BOOLQUAL Expr

Pat::=Expr

Alt::=([Pat],Rhs)

Rhs::=GUARDED[(Line,(Expr,Expr))]

|LETREC([Eqn],Rhs)

|(Line,Expr)

SigType::=QUAL([Pred],Type)

|Type

Type::=ARROW

|TUPLE

|UNIT

|LIST

|VARID

|CONID

|AP(Type,Type)

Pred::=AP(CONID,Type)

|AP(Pred,Type)

Figure4:Abstract syntax for parsed terms and types it is still quite close to the input language.Although it makes the implementation a little more compli-cated,keeping the input in this form makes it easier to give accurate error messages during static analysis and type checking.That said,there are a few exam-ples where the special syntax used in Gofer programs is not preserved.The following table shows the trans-lations used for the special syntax for right sections, unary minus and arithmetic sequences:

Source Translation

(‘op‘a)flip a

(-a)negate a

[a..b]enumFromTo a b

[a,b..]enumFromThen a b

[a..]enumFrom a

[a,b..c]enumFromThenTo a b c

Apart from the list of equations and type signatures that are returned when the end of the input?le is encountered,the parser also processes several other kinds of declaration:

?type and data de?nitions:For each type con-structor de?nition,the tyconDefn()function is used to allocate a new Tycon and to save the de-tails for further processing during static analysis.?class and instance declarations:In a similar way,new Class and Inst values are allocated us-ing classDefn()and instDefn()to record the details for each class and instance declaration in the input program,respectively.

?Primitive declarations:Bindings of variable names to internal primitives are gathered to-gether in a list primDefns during parsing using the primDefn()https://www.wendangku.net/doc/e411768419.html,ter,as part of the static analysis carried out in static.c,new Name values are allocated for each named primitive.?Fixity declarations:Precedence values and asso-ciativities for in?x operator symbols are entered into the tables used by the expression parser as soon as the?xity declarations are encountered. Note that these declarations can only appear at the top-level of an input program.

6Static analysis

The main purpose of the code in static.c is to carry out static checks and analyzes on parsed programs and expressions before they are passed on to the type checker.Most of these tasks are so mundane that we

often don’t think about them explicitly when writing programs for Gofer.For example,consider a program containing a datatype de?nition of the form:

data T a b c=C|D t1|E t2t3

where t1,t2and t3are some type expressions.To ensure that this de?nition is valid we need to carry out the following tests:

?Check that there is no previous de?nition for T, either as a type constructor or as a type class.?Check the format of the left hand side.The parser ensures that the arguments to T are simple type variables,but an additional check is needed to ensure that there are no repeated variables.

?Check that the type expressions appearing on the right hand side are well-formed.In particular,we need to ensure that:

–The only type variables involved are those on the left hand side of the de?nition.

–All of the type constructors referred to on the right hand side are de?ned somewhere

in the current program.

–The types on the right hand side are well-kinded.For example,this prevents any at-

tempts to supply a type constructor with

too many arguments.This requires a form

of kind inference and will be described in

Section7.7.

?Add new Name values with suitable types and ari-ties for each of the constructor functions C,D and

E de?ned by the right hand side.In addition,we

need to ensure that there are no previous de?-nitions for these functions in another datatype de?nition.

De?nitions for type synonyms,classes,instance, primitive,function and operator?xities are also sub-jected to static checks of a similar nature.Verifying these conditions for input programs allows the sys-tem to give early detection of simple program errors. In addition,it simpli?es the code in later sections of the compiler.For example,there is no need to deal with unbound variables during type checking or code generation.

The Gofer system allows the de?nitions in a script to be placed in any order6.As a result,many of these 6The placement of?xity declarations does have an e?ect on the way that programs are parsed.Also,the ordering of de?nitions does a?ect the order in which errors are reported to the user.However,it does not have any e?ect on the semantics of error-free programs.static checks must be delayed until the whole script ?le has been parsed.

Although the full list of static checks is quite long, most of them quite easy to implement.For the re-mainder of this section,we will concentrate on two particular features;the translation of parsed terms and types to a form that is suitable for the type checker,and the use of dependency analysis.Strictly speaking,the kind inference mechanisms used in Gofer are also part of the static analysis.How-ever,the implementation of these functions in kind.c shares some code and data structures with the main type checker and,therefore,we postpone further dis-cussion of this to Section7.7.

6.1Translation of parsed values

In addition to the checks described above,the static analysis component of the Gofer system also trans-lates parsed types and declarations into a slightly dif-ferent form.Most of the changes are motivated by the need to avoid unnecessary work in later stages.For example,identi?ers corresponding to constants such as Name s,Tycon s or Class es in input terms are re-placed with the corresponding values in translated terms,avoiding the need for further symbol table lookups.

6.1.1Translation of parsed types

Most of the work of the static analysis routines is ac-complished by‘walking’the structure of input terms, types and declarations.For example,the analysis of a parsed type expression produces a result of the form described by the grammar in Figure5.Notice that occurrences of CONID cells in the input grammar have now been replaced by the Class or Tycon values that they refer to.In a similar way,the type variables rep-resented by VARID cells in parsed types are replaced by numbered Offset s.The presence of type vari-ables,signaling a polymorphic type,is represented by POLYTYPE values,with the Sig?eld used to record the kinds of polymorphic type variables7.

A full description of the representation of polymor-phic types requires a fairly good understanding of the technical issues discussed in[33].We will illustrate the main ideas by describing the representation of the Gofer type a->m a.Following the Haskell con-vention that type variables are implicitly bound by an outermost universal quanti?er,this corresponds to 7During the preliminary stages of static analysis,the Sig ?eld is used to record the number of type variables,but not their kinds.

北京房山初三一模作文

2015北京房山区初三一模作文:诚信或春天里的故事 题目A:请根据下图提供的信息,自拟题目完成一篇作文,文体不限(诗歌除外)。 题目B:请你以下面这首古诗描写的情境为背景,展开想象,以“春天里的故事”为题写一篇作文(诗歌除外)。 春晓 孟浩然 春眠不觉晓,处处闻啼鸟.夜来风雨声,花落知多少。 要求: (1)请在答题纸上用2B铅笔将你所选题目对应的选项涂黑。 (2)请将你的文章题目写在答题纸相应的位置上。 (3)字数在600-800之间。 (4)不得出现所在学校的地名、校名或师生姓名。 范文:诚信是心灵的契约 春天杨柳依依,我留一片最嫩的,夏天大雨倾盆,我捧一滴最多情的,秋天枫叶飘飘,我采一片最火红的,冬天白雪纷飞,我采一朵最圣洁的。在人生的道路上,我要采撷最美丽的,最弥足珍贵的诚信。我要将它虔诚的放在心中,成为心灵的契约。 拥有诚信,一根小小的火柴可以燃亮一片心空,拥有诚信,一朵小小的水花可以飞溅起整个海洋,拥有诚信,就像雄鹰拥有了锐眼,只有内心注满诚信,别人才会容纳你,生活也会更美好。 有一个在德国留学的中国学生,毕业时成绩优异,但在德国四处求职时,却被很多大公司拒绝,当他选了一家小公司求职时,没想到仍被拒绝,德国人给了他一份记录,记录他乘公共汽车时,曾被抓到了三次逃票,讲述这件事的一位知名学者说,德国抽查逃票一般被查到的机率是万分之三,这位高材生被抓到三次,在严谨的德国人眼里是不可饶恕的,诚信是人之本,拥有诚信,才有更多的机会留给你。 一家大公司的总裁,在接受记者的采访时,记者问他,成功的秘诀是什么?他只回答两个字“诚信”。一个人在三毛两角的蝇头小利上都靠不住,你还能指望在别的事情上可以依赖他吗?他的话通过无线电波传到世界各地。可见诚信是人生的底线,也是一切成功之本,拥有诚信,才能让让世界更美丽。 正因为有了一诺千金的豪情,才奏出了易水送别之歌,诚信是侠客永恒的旋律;正因为有了海誓山盟的执著,才唱出了化蝶共舞之歌,诚信成为缠绵的绝唱;正因为有了为民富国强的信念,才弹出了崇洁尚廉之歌。 将诚信虔诚的放在心中,与心灵签一份契约

南京、盐城高三语文一模作文范文

稻味 作者:于越老师 谷物的香气,是一把回家的钥匙。 东北大米,不久煮,不佐料,不掺杂粮。就这一份厚实的谷香。东北人有用它待客的自信,也有与它共度余生的觉悟。 但这美味,却不是旁人能尝。 我和未婚妻算是同乡。家中有一个精致的米桶。可说是首饰细盒以外,最重要的容器。加盖密封,双层扣锁。以至于每一位首次到访的朋友,都想象着能吃到何等高级的香米,可大半确是失望了。年纪稍长不长的人,对真假格外在意,总能明白。 可我们小两口,却是吃得心宁胃暖,感慨万千,吃得流匙香满室,把酒问青天。 我的父亲早年贩过大米,作为家中的长子,十八岁出门远行,交货时,他会背着百斤的米袋,背上全家人的指望。那里有我二叔的学费,老姑(东北叫法,即小姑)的花绣。 所以,吃米饭的时候,我就知道。为什么小时候,我一到七点不起床,他就打我。 现在,他可打不动我了,肩周炎,胳膊只能平举。 我吃米饭,就权当他打我。 他老了,想把肩上的米袋给我抗着。我可禁不住。但他接下来的日子,想吃的每一口粥,我都包了。还要端到他面前,喂给他吃。 我妈姓赵,是最后一批的知青,读过书的。嫁给我爸的时候,除了米饭,什么菜也不会做。 后来,我出生了,她就什么都会了。 “今天,吃米饭” ——记忆中,每当父子回家,问起晚餐的菜色。这就是她的标准答案。 也曾一直疑惑,为什么她放着上桌的鱼肉不说,偏说这一碗平淡到近乎无趣的米饭。

直到自己接下了柴米,才似乎明白,或许是她赵大小姐内心深处唯一自信,敢拿出手的菜式了。小时候的我,以为母亲是万能的,万能的理所当然。再吃米饭的时候,回头看,她却一直是个战战兢兢的小姑娘,尽自己的一切所能,演好一个母亲。 我的母亲,就在年前,已经往生。愿她在天堂永享极乐。我却不知,既是极乐,那对她来说,彼端天国,是否会有一个儿子。 我的这碗米,大概也只有些浅薄的故事,却不知,为何爱人也吃得陶醉。她的那碗,和我的稻味,也定不相同。 这让我想起,广州的朋友,请我喝那鱼粥,在我还不知其味的时候,他就已经感怀赞叹,啧啧不绝了。 稻香自沁,稻意自清,稻味自得。 散香的记忆 作者:葛常佳老师 多年之后,当我在焕然一新的故乡小镇街道上驻足,依然会想起那个遥远的泛着爱与希望的清晨。 这一天和已过的每一天一样,平平凡凡地开始了,一个个穿着整齐校服的红领巾匆匆忙忙地向学校跑去,我也不例外。 从家到学校的路上,零零星星散布着几家寄宿班,烧好的早饭香味儿顺着打开的门窗飘散开来,每个经过的孩子都不由得停下脚步朝门内张望两眼,又不舍地跑开。 一位衣衫褴褛的乞者在孩子们的“队伍”中格外显眼,孩子们嬉笑着,捏着鼻子,小心躲避着,从乞者的旁边快速绕过。乞者的肚子咕咕地叫,看到我在看他,那黝黑的脸

深圳一模优秀作文

2017年深圳一模作文题深度分析及优秀作文 22.阅读下面的材料,根据要求写一篇不少于800字的文章。(60分)小朱向父母坦陈了自己酝酿很久的一个想法:辞职回家和父母一起养螃蟹。父亲觉得小朱好不容易读完大学,当了大公司的网络工程师,待遇又好,工作又体面;如果回家养螃蟹,这些不都白费了?母亲则建议小朱先跟着他们到蟹塘去体验一下。小朱抓了一天螃蟹,才真正体会到父母养蟹的辛苦。不过,他仍然觉得发挥自己的专长,做“电商”卖螃蟹也很有前景;如果成为镇里第一个卖螃蟹的大学生,也是挺光 彩的。 要求结合材料内容及含意,选好角度,确定立意;明确文体,自拟标题;不要套作,不得抄袭,不泄漏个人信息。 一、一些基本的审题立意示例 (一)符合题意得审题立意 1.勇于改变职业规划、实现人生最大价值(职业选择价值角度) 2.走好职业规划的每一步(职业抉择、知与行角度) 3.从小朱的选择看创业幸福((职业选择多元价值—事业亲情生活兼顾-角度) 4.和父母一起创业,不亦乐乎(职业选择多元价值—事业家庭生活兼顾—角度) 5.规划交流成长(个人职业规划成长角度) 6.从父母那里习得人生智慧(孩子接受父母建议与实践角度) 7.亦师亦友感父母辞职创业觅人生(个人职业选择和父母交流作用角度) 8.做孩子职业人生规划的朋友与导师(父母和孩子交流角度) 9.请以平等尊重的态度对待孩子的人生抉择(职业选择与父母交流角度) 10.就业与创业,贵在自我实践认知(个人职业选择角度) 11.寻找职业的价值与快乐(职业价值认知的途径角度) 12.网络工程师能“卖螃蟹”吗?(职业价值认知角度)13.创业请知与行相结合(知与行角度) 14.人生大事需要父母的参与沟通(或学会与父母沟通、年轻人角度) 15.请给职业人生道路上的孩子加油(或尽己所能、父母给孩子建议角度) 16.当好孩子职业人生的参谋(父母给孩子建议角度) 17.认知自我,做孩子人生的倾听者与建议者(父母给孩子建议角色角度) 18.良好的家庭关系是孩子人生规划最好的平台(从家庭和谐平等关系角度)17.母(或父)亲与孩子的创业(母或父亲角色角度) (二)容易跑偏或离题的审题立意 1.勇于创业 2.职业无贵贱 3.谈就业与创业 4.三人行,必有我师 5.两代人之间 6.请不要阻拦孩子实现自己的梦想 7.给孩子自由的天空 8.孝顺父母乃创业之本 9.父母在不远游 10.论代沟 11.如何处理亲子关系 12.严父慈母 13.平等尊重每一个人

初三作文之初三一模作文

初三一模作文 【篇一:2015初三一模作文题目】 2015初三一模作文题目 2015.1 【篇二:2016年中考一模作文题及相关范文整理】一.2016年上海市各县区语文一模作文题目汇集 1.浦东新区:《告别》 2.普陀:《在这里起步》 3.长宁(金山):《痛并快乐着》 4.杨浦:《你曾拨动了我的心弦》 5.闵行:《温暖的叮嘱》 6.奉贤:《另一种温度》 7.虹口:《人间自有真情在》 8.徐汇《乐趣》 9.宝山《终于找到了答案》 10.静安(青浦):《相处的时光》 11.闸北:《这一刻,竟如此动人》 12.嘉定:《这才是我最珍爱的》 13.松江:《不知不觉中,我已经改变了想法》 14.崇明:《那天,我看见了》 15.黄浦:《我,依然拥有一颗童心》 一个人长大成熟后,是不是还对一切充满着好奇?是不是还能体会 到简单的快乐?是不是一直拥有纯洁而无邪的心灵???流逝的 时光也许可以带走美好的童年,然而,我们依然可以拥有一颗童心,依然相信一切美好,依然怀抱着梦想?? 二.2016年上海市各县区一模作文范文赏读 1.题目:告别(16年浦东新区) 要求:(1)写一篇600字左右的文章。(2)不得透露个人相关信息。(3)不得抄袭。 范文: 已经两天了,我在烟雨的江南盘桓,触摸江南的灵气。但是今天, 我不得不与你告别,我挚爱的江南。

从小就读过“烟笼寒水月笼沙”“月落乌啼霜满天”的优美诗句,心中 便藏下对江南“小桥流水人家”的无限向往。去年暑假,忍不住诱惑,便报了旅行团,来到了我魂牵梦萦的江南。 江南好,风景旧曾谙。喜欢江南的质朴宁静,蒙蒙水汽间,绿水人 家绕。白墙黑瓦的老屋一座连着一座,古朴得宛如唐诗宋词的意境。细雨蒙蒙中,偶尔有一两个打伞的人从石桥上走过,那半圆的桥洞 恰与水中的倒影合成一个完美的整圆,构成一幅唯美的水墨江南画。江南的水清柔,如同绸缎般,清柔得能一眼望到底,没有任何遮拦 和悬念。这水该不会是江南女子的衣裳吧?你看,屋舍前,石桥下, 田野里,到处都是水的影子。有了水,江南才充满光鲜、灵气;有了水,江南才会成为可人的小家碧玉。悠闲地飘荡在这静静流淌的碧 绿的水上,时间的脚步也放慢了,杂芜的心事逐渐淡远,思想和灵 魂仿佛被洗涤一新:人生何尝不是一湾清水,浮躁和喧哗,功名与 利禄,皆会飘然而去,平平淡淡才是最真。 喜欢江南的院落,江南的院落与北方不同,青砖、碧瓦、白墙、木雕、石刻,高低错落的马头墙、青青光滑的石板路,爬满青藤的院墙,狭窄悠长的小巷,再配上九曲十八弯的水溪,吱呀转动的古老 水车、五颜六色飘摇的扎幌,构成了一幅美妙的素描。院落都不大,与北方院落相比,甚至显得有些狭窄,但都一律地干净整洁,渗透 着古朴和典雅。细心的主人,将院落的每一处都精心设计过,正如 叶圣陶老先生所说,无论站在哪个点上,眼前总是一幅完美的图画。不仅如此,听导游说,每一个院落还都曾有过一个动听的故事呢。 月落乌啼霜满天,乌篷船仍荡漾在桨声灯影的秦淮河上,静谧的夜里,江南更显得风情万种。桨声、灯影、箫声、流水声,再加上船 上人的笑语声,我完全陶醉了。坐在船边,我也学着她们撑起了一 把小竹伞,随着船的轻漾,仿佛走进了画里,走进了翰墨飘香的唐 诗宋词,舴艋舟驶入藕花深处?? 车子渐行渐远,我回头望着那旖旎的画面,慢慢化为一个小小的黑点,我知道,我不得不与我的江南作别了。三天的时光虽然短暂, 但江南的质朴宁静,江南的雾霭朦胧,江南的明丽清纯,早已定格 在心底,会成为我一生的记忆。 什么时候,我能再来江南? 2.题目:在这里起步 (16年普陀一模)

南京市高三一模作文题“告诉你”(整理精校版)

南京市高三一模作文题“告诉你” 作文辅导 0103 1245 南京市高三一模作文题“告诉你” 评分细则与范文 七、作文题(70分) 18.从下面两题中任选一题作文。 (1)请以“有这样一个地方”为题,写一篇不少于800字的记叙文。 (2)“告诉你”是我们经常听到的一句话,这句话引发了你哪些思考?请自拟标题,写一篇不少于800字的议论文。 一、“告诉你”的审题 这是一个看似“简单”,其实内含丰富的短语,应围绕“告诉你”三个字思考,必须是“我们听到”的,而不是“你告诉别人”的。“告诉你”可能是“命令训导式”,也可能是“交流畅谈式”,也可能是“循循善诱式”。必须进行多角度思维,可褒、可贬,亦可辩证分析。写作角度可以涉及方式、心态、情感等。 写作难点在于:①不能“化大为小”,只是泛论教育等;②关注现实不够,观点缺乏论据作证,或者与论点关系不够紧密;③容易出现“新题套旧作”现象,论述缺乏新意;④未能比较紧密地“告诉你”这句话,而是较多地阐发“告诉你”的内容;⑤仅以“告诉你”为标题,缺乏拟写标题的意识和能力。 二、评分 1.基本原则 ①曲解、误解“告诉你”的意思,牵强附会,且思想平庸、语言苍白的文章,原则上都要在及格线以下赋分。②大量阐释“告诉你”的内容,一律三类卷(含三类卷)以下赋分;③文体不规范,一律四类卷(含四类卷)以下赋分。 2.赋分等级说明 ①能紧扣“告诉你”这句话,从情感、态度、方式等方面来写,并作个性化的解读,认识独到、深刻,观点与材料统一且分析透彻,论证有层次感,语言表达富有逻辑性;或者能从一个独特的角度切入,进行层层深入的分析论证,语言智慧、幽默、犀利,标题能吸引人,可视为一类卷赋分,特别优秀的可至满分。 ②能扣住“告诉你”这句话本身,提出有意义的中心观点,并能扣住中心论点展开论证,举例恰当,论据分析能扣上论点,综合运用论证方法,层次清晰,语言准确,概括能力强,标题恰当,可视为二类卷赋分。 ③能从不同角度解读“告诉你”这句话,形成几个相关联的观点或其中某一个观点,进行分析和论证,写成常规式的议论文,但较多地阐释“告诉你”的内容,可视为三类卷赋分。 ④议论文写作的基本能力明显欠缺。如观点与论据缺乏内在联系,只列举而不作分析;虽是规范的议论文,但观点属于大话、套话,或者论据材料陈旧

早读深圳一模作文(1)

2020深圳市高考语文线上测试(高三一模)作文优秀范文欣赏 作文原题 【来自2020年高三深圳市线上统一测试】 阅读下面的材料,根据要求写作。(60 分) 在这个特殊时期,全国人民正在进行一场特别的考试:疫情防控。而作为高三学生的你,又迎来另一场特别的考试——深圳市 2020 年普通高中高三年级线上统一测试。是的,这场考试有着很特别的地方:居家、线上、没有老师监考……因为特别,你会有特别的应对,崭新的思考,深刻的启发。今后的人生中,还会有许多特别的考试,而你,就是那答卷人。请你从下列任务中任选一个,根据要求完成写作。 ①以“20 年后的你”的身份,给参加这次考试的你写一封信。 ②有人说:有监考能保证考试的结果真实可信,希望父母参与监考;有人说:不需要监考,重在自觉,考试的过程更重要。请你针对其中一个看法写一篇驳论文。 ③请你为《南方教育时报》的“教育众声”栏目写一篇关于这场线上考试的评论。 要求:结合材料,自选角度,确定立意,自拟标题;切合身份,贴合情境;符合文体特征;不要套作,不得抄袭;不得泄露个人信息;不少于 800 字。 审题分析 此题为深圳高三线上考试题。这道作文题是对2019 年全国Ⅱ卷作文题的部分仿拟,也自有其特点。命题者提供了审题指导 这里不再赘述整个题目的审题,只说说第一个任务的写作。 明确形式:书信体 明确人物身份和写信对象:20年后的你回望当下的你 思考内容:写什么?应该是由这次特别时期的考试谈开去,由当下的 考试产生的思考,以及对未来人生的预想。如居家、线上、无人监考需 要诚信和自律,也正是因着这份诚信和自律,成就了未来的自己。

假如20年后的你是一名医生,教师,公安干警,科研人员,成功商人……回忆自己后来的人生又遇到了怎样的考试,经受多少次道德、法律、良知的拷问?应该感谢年少的你,感谢那个特殊时期正在成长的你,人生处处是考场,也恰恰是当年的坚守成就了现在的自己。应该忆过去,谈当下。由线上考试谈及人生考试,谈出始终作为答卷人的你的感受和 思考。 注意情理兼备。不妨为自己设定一个当下的具体身份。 考场佳作 写作任务① 愿你披荆斩棘,步入星辰大海(54分) 作者:廖茜 过去的你: 你好!我是二十年后的你。现在的你是否还在迷茫该如何前进?2020年,在这个特殊时期里,全国人民都在进行一场特别的考试:疫情防控。每个人都想尽自己能力,咬牙坚持着走出最完美的答卷。 而作为高三的你也即将面临着一场特别的考试,一场没有老师监督的考试,所以,你该如何应对这场特殊的考试呢? 特别的考试,以一个笃定的信念,享受付出的回馈。是否想拥有孟郊“昔日龌龊不足夸,今朝放荡思无涯”心满意足的幸福感呢?是否希望自己在逐梦的路上,依靠自己的努力去完成那最美答卷呢?过去的时间,我看到了你在认真做笔记的样子,看到了你在用心听课的样子,看到了你在青春里洒下的每一滴汗水,这让我充满满满的自豪感!你要相信,你真正付出了,不枉老师的殷殷期待,也可坦然直面父母的焦灼。所以不怕万人阻挡,只怕自己的投降。 特别的考试,以一个真实的答案,接受自律的考验。古时,“无哗战士衔枚勇,下笔春蚕食叶声。”考场已经是行军的疆场了。一场无人监考的考试,不因一时的虚名而丢失诚信。一场特殊的考试也是考验我们的时候,只有平时做到扎扎实实,才能看到你想拥有的星辰。青春,离不了考试,而我们也在考验着自己。线上考试作弊确实易如反掌,而你是否会想到这样真的是自己水平,就算拿到满分你就把知识收入囊中了吗?或许更多的是懊悔与自责吧!先不论分数高低,考

上海初三语文历年各区一模优秀作文集锦(优选.)

最新文件---------------- 仅供参考--------------------已改成-----------word文本 --------------------- 方便更改 上海初三语文2015年各区一模优秀作文集锦 1、上海市2015年中考一模作文及范文(普陀区):这里也是课堂普陀区中考一模作文题目: 这里也是课堂 范文1: 我一直以一个学生的严谨的态度审视着自然,看着它不断变化并从中领悟。我想人这一辈子都是个学生,而自然,便是课堂。 我喜欢在离家不远的一座石桥上看日落。每个黄昏,夕阳以一种沉静、美好的姿态下落,我沉溺在它的余晖里面,安静地呼吸。它象征着一种终结。无数个日落、无数个黄昏,我感到日子就这样一天一天地过去了,以一种无声的方式。我开始变得惜时,因为时光是看不见的,而夕阳是看得见的。每天我坐在石桥上听到河水流动的声音,我想,那就是时光流走了。是日落让我懂得惜时。 我也喜欢草。它们顽强、蓬勃、生生不息。我看着它们神情坚定的在高大乔木的阴影下挣扎着向上的样子,我会想到那些在前辈制造的宏伟阴影里仍能创造出自己的事业的拼搏者。那是一种让人敬佩的勇敢与执着。当小草终于破土而出展现出它鲜嫩的绿色时,我发现了它们小小躯体里蕴藏着的不为人知的力量,那是像一座休眠火山一样沉默着却巨大无比的力量。是那些草告诉我:要勇敢,要坚强! 还有蚂蚁。一种以团结协作的精神而为人所知的微小生物。蚂蚁搬家,真是一个让人为之震撼的举动!它们用纤细的触角彼此沟通,用纤细的足挪动着庞然大物。我想起百威啤酒的广告,那群生动的蚂蚁,它们扛着啤酒瓶子,彼此合作,互相配合。团结从一个个细节中得到体现。这群生动的蚂蚁,让我懂得什么是真正的团结。 自然,是最精彩的课堂,只要你拥有一个学生应有的谦虚求教的态度,你所学到的,将渗透你的心灵。

南京市高三一模考场优秀作文

拥抱过去 新年致辞中常出现:“让我们拥抱未来”这样振奋人心的字句。未来的未知固然令人着迷,但过去的欢笑悲哀又怎么不令人留恋?如果说拥抱未来是对生活的热情,那么拥抱过去,便是对人生的尊重和敬仰。 “总有一天你会笑着说出曾令你悲痛欲绝的过去。”曼德拉总统在就职典礼上介绍了两位特殊的客人,他们是曼德拉在狱中的看守,他们年复一年的折磨凌辱让曼德拉的过去伤痕累累,而曼德拉却选择拥抱过去,笑着感激看守们的磨炼。“如果不能放下仇恨,那我还在狱中。”拥抱过去,是一种成长与升华。 现代传媒把余秀华推向大众,推向社会,而她怀念的却是来时的方向。“我心孤独,一如从前”“我怀念横店村的花香弥漫,春天吐出一只只蜜蜂……”她忘了自己身体的残缺,忘了人们对她作品、精神的赞美,她只是选择拥抱过去,做最初的自己,用手中的笔点燃生命的烟花。用手中的笔让“过去的一切都成为亲切的怀念。” 很多时候当我们回头看看时,发现一切不过是虚惊一场。或许我们每个人都应在自己的内心建一座博物馆,给自己一些时间静静地梳理过往,而不是因为浮躁,因为贪婪,因为恐惧而把过去搁置,一味将它怪罪给时光,人生如此,对历史更应如此。 面对历史的伤痛,我们习惯地说“过去的就让他过去吧”我们用恶搞、虚伪、华丽去掩盖历史的疤痕,面对历史记录片等作品时,评一句“这样的宏大叙事多么土气”,却对如今出现的抗日雷剧,“手撕鬼子”一类津津乐道。人们对过去、对历史的漠视令人战栗。因为这不仅是对过去的不敬,更是对未来的不屑。 中国诗坛大家牛汉的永垂不朽,体现在他可以将过去的一切不幸用幽默化为斑斓人生,更体现在他的诗不为咀嚼苦难,不为向历史报复,只为让过去、让历史从灾难中走出来,只为拥抱过去,尊重过去,让过去的深重灾难不再在中国大地上重演! 作为个体来说,拥抱过去是一种宽容,信仰,可以让生命更加的纯粹明朗,作为一个国家与民族来说,拥抱过去是一种傲骨,一种责任,拥抱过去,方能使民族屹立,永垂不朽! 评语:本文紧紧围绕“过去生活的价值”进行探讨,从与“自身相关的过去”谈起“拥抱过去”让自己成长,升华,也让自己泯恩仇,得怡然。又谈对历史的看法,,“拥抱过去”是为了尊重历史,让悲剧不再重演。 全文层层深入,鞭辟入里。 判为一类卷,65分

高考深圳一模语文作文优秀范文

2012年高考深圳一模语文作文优秀范文 深圳市一模考试语文作文题: 阅读下面的文字,根据要求作文。 在一次追思“文化昆仑”钱钟书先生的活动中,清华大学一位老师这样说:“‘修身齐家治国平天下’前面还有两句是‘格物致知、诚意正心’,这便是让我们心有所止,心在焉。钱先生学问做得如此出色,就是因为‘心在焉’”。但是看看我们周围,看看我们今天这个社会,有多少人则是“心不在焉”…… 请以“心要在焉”为题,写一篇议论文,不少于800字。 心要在焉 □向婧深圳中学高三(2)班 庄周潇洒游于世间,文与可画竹栩栩如生,只因心在焉;量子论划亮了物理的天空;《悲惨世界》震惊文坛,只因心在焉。心不在焉,幸运的苹果便不会落在你的头上;心在焉,方能傲然立于天地之间。 心在焉,先要有一颗宁静的心。这不是两耳不闻窗外事,一心只读圣贤书,而是要宠辱不惊,淡泊名利。不为欲望所缠绕,这样才能做到用心专一。 电影《七宗罪》里年轻的警官,心有顾忌,被狡猾的杀人犯利用他的妒忌与愤恨,以及获得富足生活的渴望,而被引诱开枪,要在监狱中终老一生。相反,那个年迈的黑人警察,宠辱不惊,所有心思都花在抓凶手上,自然能明辨是非,没有卷入七宗罪的漩涡,此即心在焉。 心在焉,也要有不顾一切的勇气。很多时候,全身心投入是需要勇气的,要的是不顾他人的讥讽与嘲笑,要的是失败了从头再来的勇气。化学家格林尼亚曾是一个不学无术的花花公子,成天流连于舞会与晚宴,因此当人们得知他要去学化学时,纷纷嘲笑他,他的同学也都看不起他。但格林尼亚从不掩饰自己昔日的无知,一心向学,最终发明了格氏试剂,获得诺贝尔奖。没有一往无前的勇气,前进道路上的一颗石子也能阻挡你的步伐,有了勇气,即使泰山临于前亦无所畏惧。 心在焉,更要有一种信仰。今天社会上很多人常常“心不在焉”,重要的一点就是缺乏信仰。他们终日碌碌无为,不知道为何而生活,更没有为之奋斗终生的信仰。这种信仰不限于宗教,而是对真理的追求,对生命意义的不断探索。蜚声四海的瑞士表以其精确、优雅、纯手工工艺而畅销。制表匠们一直秉持着不差一分一厘的准则,终其一生都在不断追求更精确更优雅的表。有了这种信仰,才能做到心在焉,才能做到极致。 因而我们现在要心有所止,用宁静的心和披荆斩棘的勇气,去追求自己的信仰,才能无愧于天地,无愧于社会,更无愧于自己,方能傲然立于世。心要在焉,需要我们时刻铭记。 【教师点评】

最新上海初三语文一模汇编·作文

写作(60分) 普陀区27、题目:再现那一幕 要求:(1)写一篇600字左右的文章。 (2)不得透露个人相关信息。 (3)不得抄袭。 奉贤区27、题目:这样更好 要求:(1)写一篇600字左右的文章;(2)不得透露个人相关信息,不得抄袭。 宝山区27.题目:我的新体验 要求:(1)写一篇600字左右的文章。 (2)不得透露个人相关信息。 (3)不得抄袭本试卷中的阅读材料。 (4)请注意字迹端正,卷面整洁。 松江区27.题目:终于融入其中 要求:写一篇600字左右的文章,不得透露个人相关信息,不得抄袭。 杨浦区27.请以“难忘的生日”为题,写一篇作文。 要求:1 不少于600字。 2 作文中不得出现所在学校的名称和师生姓名。 3 不得以本卷上的阅读材料作为写作内容。 闵行区题目:没错,我很喜欢 要求:(1)写一篇600字左右的文章。(2)不得透露个人相关信息。(3)不得抄袭。 崇明区27、题目:事情虽已过去 要求:(1)写一篇600字左右的文章;(2)不得透露个人相关信息;(3)不得抄袭。虹口区25、题目:是花儿总要绽放 要求:(1)不得抄袭;(2)不得透露个人信息;(3)写一篇600左右的文章。 嘉定区 27、题目:难忘的约定 要求:(1)写一篇600字左右的文章 (2)不得透露个人相关信息 (3)不得抄袭 金山长宁 27、题目:我逐渐了解了他(她) 要求:(1)写一篇600字左右的文章;(2)不得透露个人相关信息;(3)不得抄袭。 静安区 26、题目:往事让人回味 要求:①这份试卷中出现过的素材请不要使用。②字数600字左右。③不要透露个人相关信息(如与本人有关的校名和姓名),若不可避免,用代号表示,如A中学、B老师、小C。④卷面整洁,字迹清楚。 青浦区 27.题目:我对自己说:加油! 要求:1.写一篇600字左右的文章。 2.不得透露个人相关信息。

2019年南京各区一模语文试卷分类:语基与作文含精品解析

初三复习专题训练:语基与作文 1.用正楷字或行楷字抄写下面的诗句。(4分)(2019年溧水一模卷) 腹有诗书气自华 2.诗歌名句积累与运用。(6分) (1)儿童散学归来早, 。 (高鼎《村居》) (2) ,山雨欲来风满楼。 (许浑《咸阳城东楼》) (3)根据以下线索写出一句诗: , 。 A.李白 B.思乡之情 C.《折杨柳》曲 D.七言绝句 (4)小辛在准备自己的课前三分钟演讲,主题为“无言之美”。下列选项中的诗歌不适合作为演讲素材 的一项是( )。 A.持节云中,何日遣冯唐。 (苏轼《江城子·密州出猎》) B.沉舟侧畔千帆过,病树前头万木春。 (刘禹锡《酬乐天扬州初逢席上见赠》) C.树梢树枝树根根,亲山亲水有亲人。 (贺敬之《回延安》) D.远远的街灯明了,好像闪着无数的明星。 (郭沫若《天上的街市》) 3.给加点字注音,根据拼音写汉字。(3分)(2019年玄武一模卷) 从你的一座庭院 观赏亘. ( )古已有的繁星, 坐在夜幕下的长凳上n íng ( )望 天体的寒光荧荧, 聆听从看不见的池塘传来的 溪流淙淙, 呼吸素馨与忍冬的芳菲, 感受睡鸟的沉寂、 门廊的静穆、湿气的蒸t éng ( ) ——这一切,也许,就是诗情。 4.用诗文原句填空。(9分) (1)念天地之悠悠, 。 (陈子昂《登幽州台歌》) (2)忽如一夜春风来, 。 (岑参《白雪歌送武判官归京》) (3) ,柳暗花明又一村。 (陆游《游山西村》) (4)文人爱水。王湾《次北固山下》中的“ ”一句亮出水之色彩;张养浩《山坡羊·潼关怀古》中的“ ”一句呈现水之澎湃;李白《赠汪伦》中“ , ”两句借水抒情;流水不止,引发孔子对时间的感叹:“ , 。” 5.用诗文原句填空。(8分)(2019年栖霞一模卷) (1) ,君子好逑。 (《诗经》 )

2019深圳一模前20名优秀作文点评_高中作文

2019深圳一模前20名优秀作文点评 坪山高中语文教师点评 1.“万马奔腾”与“一骑绝尘”(55.5分) 独马出征难败军,孤木独立难成林。万马奔腾的豪放,不输一骑绝尘睥睨的身姿;群竹成林,不输梅花独立孤傲的风采。(开门见山,观点鲜明,句式整饬,有吸引力。) 一骑绝尘的独领风骚,比不上万马奔腾的雄奇壮观。(按语:简明扼要地表达了论点,思路清晰。)远望一骑逍遥天际似乎有着别样的潇洒,但怎比得上万马飞驰而过尘土飞扬来得震撼人心魄。(此句可见作者已有成熟的思考能力。)就有如一人台上演出,没有音响,没有环境,没有气氛,没有灯光,纵你技艺再精,也不过孤芳自赏。(比喻贴切,通俗易懂,又形象生动。) 一骑绝尘即便有万夫莫开的傲人姿态,终不如万马奔腾众志成城的威武景象。(紧紧围绕主旨。)一骑绝尘,便有再大的能耐不过是用尾扫起一抔尘土散漫开来留人一个孤傲的背影(此句过长,“散漫开来”后加上逗号会更好。)又怎比得上万马奔腾开天辟地的气势以及破山裂石的力量。虎牢城关,吕奉先一人当关,有万夫莫开之势也无匹之之力,终成三英之名;乌江江头,项羽终是寡不敌众,自刎江畔。一骑绝尘的潇洒终究是被万马奔腾的气势所湮没。(按语:此段可见阅读功底,有一定的知识积累,对素材的运用较为贴切。) 1 / 10

两方交战,气势为先。(紧扣中心。)谁都不能否认张翼德长板坡(此处为错别字,应写为“长坂坡”。)上的气势磅礴,谁都不能否认高庞枪挑十余铁滑车的气势冲天,也没有人能否认斯巴达克斯在面对罗马第一军时的气势如虹。(素材丰富,令人眼前一亮。排比句式,很有说服力。)一骑绝尘有着独领风骚的气势,亦不可小觑,更不可说不震撼人心,但相较万马奔腾而言,这仅是小势。(按语:此句一出,可见作者有很强的理性思维能力。)古代最令人震撼的便是那幅“黑云压城城欲摧”的景象,即便身不在其中,也如在其境,十分震撼人心。想必如果一骑绝尘与万马奔腾相撞,前者立刻或被摧毁,而哪个场面更加震撼,就立分高下了(此句将二者直接对比,更能让人信服。本段从另一个角度论证自己的观点,有层层深入之感。)多方竞争,气势为先。(从“双方”到“多方”,观点似有递进,但是如此说理似乎不是很有必要。)一个人有气势,一群人更有气势。每个人在进行事业(按语:搭配不当。)时背后都会站着一群人,也有个别孤芳自傲,遗世独立。(此句欠流畅。)背后有一群人支持,即便没有钱的支持,没有技能的支持,这股气势有如浩瀚大海、磅礴云山,令人震撼,而因这股气势造就的成功也令人震撼。(文中多次出现“气势”、“震撼”这两个词语,似有才穷之态,读来不甚畅快。)于是,这个群体汇成一股万马奔腾的气势。而一个人没有他人的支持,甚至足够优秀(关联词不当,“甚至”应改为“即使”。),但也只能形成一缕一骑绝尘的气势(按语:“但”有些多余,可删去。“一缕” 2 / 10

(word完整版)上海初三语文历年各区一模优秀作文集锦

上海初三语文2015年各区一模优秀作文集锦 1、上海市2015年中考一模作文及范文(普陀区):这里也 是课堂 普陀区中考一模作文题目: 这里也是课堂 范文1: 我一直以一个学生的严谨的态度审视着自然,看着它不断变化并从中领悟。我想人这一辈子都是个学生,而自然,便是课堂。 我喜欢在离家不远的一座石桥上看日落。每个黄昏,夕阳以一种沉静、美好的姿态下落,我沉溺在它的余晖里面,安静地呼吸。它象征着一种终结。无数个日落、无数个黄昏,我感到日子就这样一天一天地过去了,以一种无声的方式。我开始变得惜时,因为时光是看不见的,而夕阳是看得见的。每天我坐在石桥上听到河水流动的声音,我想,那就是时光流走了。是日落让我懂得惜时。 我也喜欢草。它们顽强、蓬勃、生生不息。我看着它们神情坚定的在高大乔木的阴影下挣扎着向上的样子,我会想到那些在前辈制造的宏伟阴影里仍能创造出自己的事业的拼搏者。那是一种让人敬佩的勇敢与执着。当小草终于破土而出展现出它鲜嫩的绿色时,我发现了它们小小躯体里蕴藏着的不为人知的力量,那是像一座休眠火山一样沉默着却巨大无比的力量。是那些草告诉我:要勇敢,要坚强! 还有蚂蚁。一种以团结协作的精神而为人所知的微小生物。蚂蚁搬家,真是一个让人为之震撼的举动!它们用纤细的触角彼此沟通,用纤细的足挪动着庞然大物。我想起百威啤酒的广告,那群生动的蚂蚁,它们扛着啤酒瓶子,彼此合作,互相配合。团结从一个个细节中得到体现。这群生动的蚂蚁,让我懂得什么是真正的团结。

自然,是最精彩的课堂,只要你拥有一个学生应有的谦虚求教的态度,你所学到的,将渗透你的心灵。 范文2: 人一辈子,都像个学生,生活,则是我们最好的老师。她会教你坚强、勇敢、永不放弃。当你在生活中学会了这些,你也会像我一样感叹:“这也是课堂啊!” 考场失利,心情沮丧。那段时间,好像天空都是灰色的。我只想一个人呆在房间里,不动也不思考,只是对着天花板发呆。妈妈叫了我几次,均是无功而返,我好像对什么都失去了兴趣。 那天,爸爸出乎意料地说想和我下盘棋。我本来不想答应,但在他的坚持下,勉强拿起了棋子。下棋过程中,我们俩都没说话,可是很快,我就发现我就要全军覆没了。我叹一口气,说:“我认输了!” 爸爸抬起头来看看我,我从没发现他的眼睛竟如此深邃。他问:“为什么要放弃?”我垂头丧气地说:“已经没有希望了。”心中好像更加失落。 爸爸却说:“那现在我们换一换,你用我的棋,我用你的棋,怎样?” 我惊诧地抬起头,看着爸爸,那双平时慈祥的眼睛中仿佛充满了智慧。带着震惊与疑问,我答应了。 可是爸爸只动了几步,局势就开始逆转。我惊讶地发现我原来的那一方居然有这么大的力量!接下来爸爸每走一步棋,我心中的懊悔就加重一分。其实那几步棋我也可以想到的。我不禁在怪自己:当初为什么要放弃?

2017年深圳一模作文《多元择业,勇于创新》

2017深圳一模高分作文点评:多元择业,勇敢创新【原题】22.阅读下面的材料,根据要求写一篇不少于800字的文章。(60分) 小朱向父母坦陈了自己酝酿很久的一个想法:辞职回家和父母一起养螃蟹。父亲觉得小朱好不容易读完大学,当了大公司的网络工程师,待遇又好,工作又体面;如果回家养螃蟹,这些不都白费了?母亲则建议小朱先跟着他们到蟹塘去体验一下。小朱抓了一天螃蟹,才真正体会到父母养蟹的辛苦。不过,他仍然觉得发挥自己的专长,做“电商”卖螃蟹也很有前景;如果成为镇里第一个卖螃蟹的大学生,也是挺光彩的。 要求结合材料内容及含意,选好角度,确定立意;明确文体,自拟标题;不要套作,不得抄袭,不得泄漏个人信息。 多元择业,勇敢创新 深圳外国语学校高健58分 跳出“农门”的大学生小朱在思虑许久后决定辞职回乡养螃蟹。在“大众创新,万众创业”的春风下,做出像小朱的决定一样的年轻人不在少数。在我看来,我们确实需要打破择业单一、职业有优劣之分的社会藩篱,拾起青春的梦想,迈出一条属于自己的创业之路。(“打破择业单一、职业有优劣之分的…”、“迈出创业之路”已经奠定了文章的骨架。可见开篇定调定向的重要。) ②诚然,(不用“诚然”的让步更好,它与后面一句话中的“仍然”有冲撞。)公务员“万人求一职”的盛况或许仍然可见,但如今“铁饭碗”已不太受青年们的青睐。多元择业意识已深入人心。(“多元择业”核心词语出现。)小朱有高学历,高科技,若投身在自己打小就熟知的养蟹领域,势必将给养蟹业带来发展。由此可见,小朱选择之正确和小朱思想之开放。(“思想之开放”指向时代,正好引出下一段的写作。) ③“单一择业”,“职业有优劣之分”的思想早已过时,将知识技能应用于实践,专注于自己感兴趣的领域,难道不是明智之举吗?小朱选择做电商养蟹,正是 ..将科技与传统结合为一体,既.发挥了自身特长又.能带领乡亲们脱贫致富。(析事言理,从小到大有 层次。)而假如 ..始终无法接地气, ..待遇好,但是 ...小朱始终囿于网络工程师的职业,虽然 贴近乡亲们的生活。(这个复句关系可学!)如.从发展的前景来看,养蟹电商业正是 ..朝阳 行业,而.网络工程师因为 ..如此,小朱选择电商卖螃蟹实...人员过多,难以脱颖而出。正是 为.明智之举。 ④摘掉择业时的有色眼镜,认清发展方向,勇于开拓创新的精神值得肯定。《肖申克的救赎》中有言:“有些鸟儿是管不住的,因为它们心中有梦想,每一片羽毛上都洒满太阳的光芒。”(炫才之句也增色。)文中小朱亲身实践了养蟹业,从其中的苦品出了快乐。小朱若认准了做电商买螃蟹,沿着这条路开拓下去,必然能寻到宝藏。(“必然”一词过于绝对,不妨用“即便是失败,但这份开拓创新的精神会更显珍贵”,使分析更辩证些。)创业者最需要的就是勇气与毅力。当特斯拉创始人埃隆马斯克打算投身航天领域时,所有人都认为他疯了,而埃隆却以人类第一次回收火箭的实际行动证明了自己。小朱需要像埃隆一样有恒定的目标与决心,创作出自己的养蟹、电商帝国。(事例横比,只不过“电商帝国”有些夸大。) ⑤在“互联网+”的大时代中,葆有一颗勇于开拓进取的恒心并且舍弃职业单一的

2020海淀区初三一模优秀作文北京的美

1北京的美 我时常游览北京的玉渊潭公园,去体味北京的美。 早晨,刚踏入公园便能听见那一声声诵读诗文的声音,“会当凌绝顶,一览众山小”那是李白年少时的雄心壮志。“采菊东篱下,悠然见南山”那是陶渊明的悠闲安逸。这声音有时带着力量,充满着希望;有时又清脆安静如泉水,散发着宁静与悠然。它好像传自于几千年前的孩子的学堂,又好像就在我身边似的,伴随着吹来的清风和树叶“沙沙”的响声,我竟渐渐沉醉……这文化将古今勾连起来。在北京,我发现了文化的美。 晌午,一位白发苍苍的老人坐在洁白的原椅上,摆好毛毡,铺好一张宣纸,取一支精瘦的兼毫,吸饱墨汁,仔细研读着颜真卿的《多宝塔贴》,观察每一个字的结构与笔画的长短粗细。直到每一个字的形象都了然于心中,他的眼神忽然一顿,紧紧握住笔杆,落笔于洁白如玉的纸上,一个抬手起笔,又一个压腕儿顿笔,一个漂亮的起头完成啦。笔画流转间,他的手心里竟渗出了汗。清雅的水墨落在宣纸上,汇聚成一条美丽芬芳的兰溪。那清新飘逸的临帖,骨力劲峭的碑文,清远雄浑的楷书……这些古老遥远的文字,竟会散发出如此动人心魄的美,彰显着中华文化的魅力。在北京,我发现了文化的美。 黄昏,一位身着素衣的女子坐在古筝旁边,执琴演奏琴曲《高山流水》。清脆空灵,如芙蓉泣露般优美。她的身体前后起伏,就如翻涌的浪花;她的手指在琴弦上跳跃,就像蝴蝶翩翩起舞。后来琴曲速度加快,她奋力弹奏着,身体的每一个细胞都在呐喊,她的额间也渗出了汗,手指微酸,可她仍不停歇。我情不自禁地融入她的世界里去。这简单的二十一根弦,竟能奏出天籁之音,这便是文化所能及。在北京,我发现了文化的美。 傍晚,躺在床上,一天看到的景象在脑中浮现,北京的文化美,深入我心。 啊,北京,真美!供稿 2北京的美 时光清浅,岁月嫣然。北京,这座古韵的城,亦是在光阴与岁月的沉积之中,绽放出别样的美丽。 一场与北京小吃的邂逅,是味蕾与食物的碰撞,显现北京别样的美。忆儿时,在那黑砖白瓦的胡同里,在那心生暖意的阳光下,我总会拿起一串冰糖葫芦,看那圆溜溜的山楂,包裹着如水晶般剔透闪耀的糖衣,在阳光下散发着柔和的光芒,令人垂涎欲滴。于是我便迫不及待地轻轻地咬下一口,让糖衣渐渐融化在口中,那味道清甜不腻,酸甜可口,在口中越来越醇厚,弥漫着简单而又幸福的味道,仿佛一切都是那么的美好。后来,在繁忙之中我总是抽出时间,回到了那片古朴典雅的胡同之中,依旧能够看到,那站在烈日炎炎下的老爷爷,卖着熟悉的冰糖葫芦…..再次品尝,已不再是儿时的香甜,更是一种醇厚,一种回忆….也许岁月老去了他的容颜,皱纹在他的脸上蔓延开来,可是那份手艺,会永远留存于北京这片土地。我想,这便是北京的美吧,美在色香,更美在那份沉甸甸的回忆,那份发自心底的坚守…… 一场与老北京的胡同的相逢,携一段城南旧事而来,亦是感悟到北京的美。当晚风拂过杨柳岸,夕阳为旧物镀上日落的色彩,走在那古老的巷陌里,一种温暖浸润在心头。我看到

2020南京市 一模高分作文汇总

2020年南京一模作文 先辈们敬粮食若神明,不容丝毫亵渎。粮食有生命,有灵性,吃饭不只是得口舌之快,还是生命与生命的相遇,人们咀嚼粮食也是咀嚼时光。人与粮食同行,有辛苦,有温暖,有感恩,有敬畏。 【高分作文68分】 记忆中的绿色 微风拂过绿油油的田野,湿热的空气里,和着清新的泥土气息,我坐在窗边静静地看着远处穿行于田垄的奶奶,他背着一个蓝色的大盒子,手中拿着喷头为饱受害虫和杂草之苦的稻送上无微不至的关怀。 “奶奶,我也想去插秧。”不久前我拖着奶奶央求和她一起。 “很累的,你还小,等你长大了就带你去,而且水里有会吸人血的蚂蝗,很吓人的哦!” “小时候的我听到这都被吓得不轻。” 月上梢头,奶奶疲惫的从田里回来,我却总是问上问下,缠着她给我讲土地的故事,他拿出一本暗黄的书,它的封面十分褶皱,边边角角都是磨损的痕迹,一看就上了年头,奶奶翻到其中一页拿给我看,我小声的读了出来: “锄禾日当午,汗滴禾下土,谁知盘中餐?粒粒皆辛苦。” 这首小诗就像刚刚破土而出的豆芽一样,给了懵懂的我以希望与震撼,周末是爸爸妈妈从工作的城市回家的日子,我们四个人围桌而坐,谈笑风生,吃完饭,爸爸惊讶地说:“小宝长大了,吃饭居然没有把饭撒得到处都是。他以前啊,吃完饭,脸上、身上、桌上都是米粒。” 大家都捧腹大笑,我也开心地笑了,我看着门口平铺在地上晒着的金黄的穗粒,那是土地的承诺。 我长大了,父母便把我带到大城市念书,没想到老家竟然通了高铁,只要一小时就能到达,第一次坐高铁的,我十分好奇,央求了一个靠窗的位置,但当列车疾驰驶,我突然感到一阵刺痛。 青葱的稻田上是飞驰的列车,是高耸的桥墩,他们有的早已荒芜,有的则被铁轨分成两个部分,让农民难以越过。 身旁的爸爸妈妈在笑着赞叹高铁的便利,坐在对面的陌生人把吃了一半的面包随手丢弃,邻坐的大妈在抱怨米价从两块涨到了两块二,电视里的新闻播放着粮食增产的喜报。 可当我看到我国高铁总里程再次刷新时,我常常质疑那新增的线路又迫使多少农田弃置。在学校里看着迎战高考的同学们,一边背着“一粥一饭,当思来之不易”,一边把剩饭倒进快要装满的厨余垃圾箱。我也十分痛心,我痛心我做不了什么,除了不浪费自己的饭菜,我又能做什么?难道节约粮食,他们并不知晓吗? 到了假期,爸爸将奶奶也接到了大城市,爸爸很快乐,说让奶奶享受几年福,我偷偷问奶奶那家里地呢? “三亩地种一年就2000多块钱,还种什么惶子!” 【高分作文65分】 偎依 “每一个人偎依着大地孤独地裸露在阳光下。” 诗人萨瓦多尔·夸西莫多在诗中这样写道。

2017深圳一模优秀作文和详细评价

【原题】22.阅读下面的材料,根据要求写一篇不少于800字的文章。(60分) 小朱向父母坦陈了自己酝酿很久的一个想法:辞职回家和父母一起养螃蟹。父亲觉得小朱好不容易读完大学,当了大公司的网络工程师,待遇又好,工作又体面;如果回家养螃蟹,这些不都白费了?母亲则建议小朱先跟着他们到蟹塘去体验一下。小朱抓了一天螃蟹,才真正体会到父母养蟹的辛苦。不过,他仍然觉得发挥自己的专长,做?电商?卖螃蟹也很有前景;如果成为镇里第一个卖螃蟹的大学生,也是挺光彩的。要求结合材料内容及含意,选好角度,确定立意;明确文体,自拟标题;不要套作,不得抄袭,不得泄漏个人信息。 1.多元择业,勇敢创新 深圳外国语学校高健58分 跳出?农门?的大学生小朱在思虑许久后决定辞职回乡养螃蟹。在?大众创新,万众创业?的春风下,做出像小朱的决定一样的年轻人不在少数。在我看来,我们确实需要打破择业单一、职业有优劣之分的社会藩篱,拾起青春的梦想,迈出一条属于自己的创业之路。(?打破择业单一、职业有优劣之分的…?、?迈出创业之路?已经奠定了文章的骨架。可见开篇定调定向的重要。) ②诚然,(不用?诚然?的让步更好,它与后面一句话中的?仍然?有冲撞。)公务员?万人求一职?的盛况或许仍然可见,但如今?铁饭碗?已不太受青年们的青睐。多元择业意识已深入人心。(?多元择业?核心词语出现。)小朱有高学历,高科技,若投身在自己打小就熟知的养蟹领域,势必将给养蟹业带来发展。由此可见,小朱选择之正确和小朱思想之开放。(?思想之开放?指向时代,正好引出下一段的写作。)

③?单一择业?,?职业有优劣之分?的思想早已过时,将知识技能应用于实践,专注于自己感兴趣的领域,难道不是明智之举吗?小朱选择做电商养蟹,正是将科技与传统结合为一体,既发挥了自身特长又能带领乡亲们脱贫致富。(析事言理,从小到大有层次。)而假如小朱始终囿于网络工程师的职业,虽然待遇好,但是始终无法接地气,贴近乡亲们的生活。(这个复句关系可学!)如从发展的前景来看,养蟹电商业正是朝阳行业,而网络工程师因为人员过多,难以脱颖而出。正是如此,小朱选择电商卖螃蟹实为明智之举。 ④摘掉择业时的有色眼镜,认清发展方向,勇于开拓创新的精神值得肯定。《肖申克的救赎》中有言:?有些鸟儿是管不住的,因为它们心中有梦想,每一片羽毛上都洒满太阳的光芒。?(炫才之句也增色。)文中小朱亲身实践了养蟹业,从其中的苦品出了快乐。小朱若认准了做电商买螃蟹,沿着这条路开拓下去,必然能寻到宝藏。(?必然?一词过于绝对,不妨用?即便是失败,但这份开拓创新的精神会更显珍贵?,使分析更辩证些。)创业者最需要的就是勇气与毅力。当特斯拉创始人埃隆马斯克打算投身航天领域时,所有人都认为他疯了,而埃隆却以人类第一次回收火箭的实际行动证明了自己。小朱需要像埃隆一样有恒定的目标与决心,创作出自己的养蟹、电商帝国。(事例横比,只不过?电商帝国?有些夸大。) ⑤在?互联网+?的大时代中,葆有一颗勇于开拓进取的恒心并且舍弃职业单一的陈旧思想确实重要。(段落核心句意识!)上交大的李宏烨以材料学博士身份跨入相声界,北大建筑系高材生石悦也勇敢地进入了游戏领域都深刻体现着多元择业意识的深入人心。苏轼有云:?古今之成大事业者,非惟有超世之才,亦必有坚韧不拔之志。?(再次显才炫才。)笃定目标,勇敢地迈出人生的脚步,将每一步走的扎实,那么千千万万像小朱一般的创业者,们即可计日而待成功之时了。 ⑥让我们选择自己热爱的事业,驾着人生之舟远航吧!(呼告结束。) 【总评】从题目看,“多元择业,勇于创新”两个短语各有所指,又互有关联。“多元择业”是与时代大背景有关,“勇于创新”则更多的是指向小朱这样的大学生。二者有关系则是要在“多元择业”的大背景下“勇于创新”,当然,二者的关系,是“多元择业”依靠于“勇于创新”。这样一关联,就有了从一个人到一个群体,再到一个时代的宏大意旨,所以,文章开头段的一句“我们确实需要打破择业单一、职业有优劣之分的社会藩篱,拾起青春的梦想,迈出一条属于自己的创业之路”,既是文章观点,更是文章的二元内容的总起;与之相对应的是,在文章结尾句中,呼告对象变成了“我们”。

相关文档
相关文档 最新文档