source: src/Parser/ParseNode.h @ e04ef3a

aaron-thesisarm-ehcleanup-dtorsctordeferred_resndemanglerenumforall-pointer-decaygc_noraiijacob/cs343-translationjenkins-sandboxmemorynew-astnew-ast-unique-exprnew-envno_listpersistent-indexerpthread-emulationqualifiedEnumresolv-newwith_gc
Last change on this file since e04ef3a was e04ef3a, checked in by Peter A. Buhr <pabuhr@…>, 7 years ago

add gcc extension, first attempt, not done yet

  • Property mode set to 100644
File size: 20.6 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// ParseNode.h --
8//
9// Author           : Rodolfo G. Esteves
10// Created On       : Sat May 16 13:28:16 2015
11// Last Modified By : Peter A. Buhr
12// Last Modified On : Mon Jun 13 16:04:47 2016
13// Update Count     : 240
14//
15
16#ifndef PARSENODE_H
17#define PARSENODE_H
18
19#include <string>
20#include <list>
21#include <iterator>
22#include <memory>
23
24#include "Common/utility.h"
25#include "Parser/LinkageSpec.h"
26#include "SynTree/Type.h"
27#include "SynTree/Expression.h"
28//#include "SynTree/Declaration.h"
29#include "Common/UniqueName.h"
30
31class ExpressionNode;
32class CompositeExprNode;
33class CommaExprNode;
34class StatementNode;
35class CompoundStmtNode;
36class DeclarationNode;
37class InitializerNode;
38
39// Builder
40class ParseNode {
41  public:
42        ParseNode();
43        ParseNode( const std::string * );
44        ParseNode( const std::string & );  // for copy constructing subclasses
45        virtual ~ParseNode();
46
47        ParseNode *get_link() const;
48        ParseNode *get_last();
49        ParseNode *set_link( ParseNode * );
50        void set_next( ParseNode *newlink ) { next = newlink; }
51
52        virtual ParseNode *clone() const { return 0; };
53
54        const std::string &get_name() const { return name; }
55        void set_name( const std::string &newValue ) { name = newValue; }
56
57        virtual void print( std::ostream &, int indent = 0 ) const;
58        virtual void printList( std::ostream &, int indent = 0 ) const;
59
60        ParseNode &operator,( ParseNode &);
61  protected:
62        std::string name;
63        ParseNode *next;
64        static int indent_by;
65};
66
67ParseNode *mkList( ParseNode & );
68
69class ExpressionNode : public ParseNode {
70  public:
71        ExpressionNode();
72        ExpressionNode( const std::string * );
73        ExpressionNode( const ExpressionNode &other );
74        virtual ~ExpressionNode() { delete argName; } // cannot delete argName because it might be referenced elsewhere
75
76        virtual ExpressionNode *clone() const = 0;
77
78        virtual CommaExprNode *add_to_list( ExpressionNode * );
79
80        ExpressionNode *get_argName() const { return argName; }
81        ExpressionNode *set_argName( const std::string *aName );
82        ExpressionNode *set_argName( ExpressionNode *aDesignator );
83        bool get_extension() const { return extension; }
84        ExpressionNode *set_extension( bool exten ) { extension = exten; return this; }
85
86        virtual void print( std::ostream &, int indent = 0) const = 0;
87        virtual void printOneLine( std::ostream &, int indent = 0) const = 0;
88
89        virtual Expression *build() const = 0;
90  protected:
91        void printDesignation ( std::ostream &, int indent = 0) const;
92  private:
93        ExpressionNode *argName = 0;
94        bool extension = false;
95};
96
97template< typename T >
98struct maybeBuild_t<Expression, T> {
99        static inline Expression * doit( const T *orig ) {
100                if ( orig ) {
101                        Expression *p = orig->build();
102                        p->set_extension( orig->get_extension() );
103                        return p;
104                } else {
105                        return 0;
106                } // if
107        }
108};
109
110// NullExprNode is used in tuples as a place-holder where a tuple component is omitted e.g., [ 2, , 3 ]
111class NullExprNode : public ExpressionNode {
112  public:
113        NullExprNode();
114
115        virtual NullExprNode *clone() const;
116
117        virtual void print( std::ostream &, int indent = 0) const;
118        virtual void printOneLine( std::ostream &, int indent = 0) const;
119
120        virtual Expression *build() const;
121};
122
123class ConstantNode : public ExpressionNode {
124  public:
125        enum Type { Integer, Float, Character, String };
126
127        ConstantNode( Type, std::string * );
128        ConstantNode( const ConstantNode &other ) : type( other.type ), btype( other.btype), value( *new std::string( other.value ) ) {};
129        ~ConstantNode() { delete &value; }
130
131        virtual ConstantNode *clone() const { return new ConstantNode( *this ); }
132        Type get_type( void ) const { return type; }
133        virtual void print( std::ostream &, int indent = 0) const;
134        virtual void printOneLine( std::ostream &, int indent = 0) const;
135
136        const std::string &get_value() const { return value; }
137        ConstantNode *appendstr( const std::string *newValue );
138
139        Expression *build() const;
140  private:
141        Type type;
142        BasicType::Kind btype;
143        std::string &value;
144};
145
146class VarRefNode : public ExpressionNode {
147  public:
148        VarRefNode();
149        VarRefNode( const std::string *, bool isLabel = false );
150        VarRefNode( const VarRefNode &other );
151
152        virtual Expression *build() const ;
153
154        virtual VarRefNode *clone() const { return new VarRefNode( *this ); }
155
156        virtual void print( std::ostream &, int indent = 0 ) const;
157        virtual void printOneLine( std::ostream &, int indent = 0 ) const;
158  private:
159        bool isLabel;
160};
161
162class DesignatorNode : public ExpressionNode {
163  public:
164        DesignatorNode( ExpressionNode *expr, bool isArrayIndex = false );
165        DesignatorNode( const DesignatorNode &other );
166
167        virtual Expression *build() const ;
168        virtual DesignatorNode *clone() const { return new DesignatorNode( *this ); }
169
170        virtual void print( std::ostream &, int indent = 0 ) const;
171        virtual void printOneLine( std::ostream &, int indent = 0 ) const;
172  private:
173        bool isArrayIndex;
174};
175
176class TypeValueNode : public ExpressionNode {
177  public:
178        TypeValueNode( DeclarationNode * );
179        TypeValueNode( const TypeValueNode &other );
180
181        DeclarationNode *get_decl() const { return decl; }
182
183        virtual Expression *build() const ;
184
185        virtual TypeValueNode *clone() const { return new TypeValueNode( *this ); }
186
187        virtual void print( std::ostream &, int indent = 0) const;
188        virtual void printOneLine( std::ostream &, int indent = 0) const;
189  private:
190        DeclarationNode *decl;
191};
192
193class OperatorNode : public ExpressionNode {
194  public:
195        enum Type { TupleC, Comma, TupleFieldSel, // n-adic
196                                // triadic
197                                Cond, NCond,
198                                // diadic
199                                SizeOf, AlignOf, OffsetOf, Attr, Plus, Minus, Mul, Div, Mod, Or, And,
200                                BitOr, BitAnd, Xor, Cast, LShift, RShift, LThan, GThan, LEThan, GEThan, Eq, Neq,
201                                Assign, MulAssn, DivAssn, ModAssn, PlusAssn, MinusAssn, LSAssn, RSAssn, AndAssn, ERAssn, OrAssn,
202                                Index, FieldSel, PFieldSel, Range,
203                                // monadic
204                                UnPlus, UnMinus, AddressOf, PointTo, Neg, BitNeg, Incr, IncrPost, Decr, DecrPost, LabelAddress,
205                                Ctor, Dtor,
206        };
207
208        OperatorNode( Type t );
209        OperatorNode( const OperatorNode &other );
210        virtual ~OperatorNode();
211
212        virtual OperatorNode *clone() const { return new OperatorNode( *this ); }
213
214        Type get_type() const;
215        const char *get_typename() const;
216
217        virtual void print( std::ostream &, int indent = 0) const;
218        virtual void printOneLine( std::ostream &, int indent = 0) const;
219
220        virtual Expression *build() const { return 0; }
221  private:
222        Type type;
223};
224
225class CompositeExprNode : public ExpressionNode {
226  public:
227        CompositeExprNode();
228        CompositeExprNode( const std::string * );
229        CompositeExprNode( ExpressionNode *f, ExpressionNode *args = 0 );
230        CompositeExprNode( ExpressionNode *f, ExpressionNode *arg1, ExpressionNode *arg2 );
231        CompositeExprNode( const CompositeExprNode &other );
232        virtual ~CompositeExprNode();
233
234        virtual CompositeExprNode *clone() const { return new CompositeExprNode( *this ); }
235        virtual Expression *build() const;
236
237        virtual void print( std::ostream &, int indent = 0) const;
238        virtual void printOneLine( std::ostream &, int indent = 0) const;
239
240        void set_function( ExpressionNode * );
241        void set_args( ExpressionNode * );
242
243        void add_arg( ExpressionNode * );
244
245        ExpressionNode *get_function() const;
246        ExpressionNode *get_args() const;
247  private:
248        ExpressionNode *function;
249        ExpressionNode *arguments;
250};
251
252class AsmExprNode : public ExpressionNode {
253  public:
254        AsmExprNode();
255        AsmExprNode( ExpressionNode *inout, ConstantNode *constraint, ExpressionNode *operand ) : inout( inout ), constraint( constraint ), operand( operand ) {}
256        virtual ~AsmExprNode() { delete inout; delete constraint; delete operand; }
257
258        virtual AsmExprNode *clone() const { return new AsmExprNode( *this ); }
259        virtual Expression *build() const;
260
261        virtual void print( std::ostream &, int indent = 0) const;
262        virtual void printOneLine( std::ostream &, int indent = 0) const;
263
264        ExpressionNode *get_inout() const { return inout; };
265        void set_inout( ExpressionNode *newValue ) { inout = newValue; }
266
267        ConstantNode *get_constraint() const { return constraint; };
268        void set_constraint( ConstantNode *newValue ) { constraint = newValue; }
269
270        ExpressionNode *get_operand() const { return operand; };
271        void set_operand( ExpressionNode *newValue ) { operand = newValue; }
272  private:
273        ExpressionNode *inout;
274        ConstantNode *constraint;
275        ExpressionNode *operand;
276};
277
278class LabelNode : public ExpressionNode {
279  public:
280        virtual Expression *build() const { return NULL; }
281        virtual LabelNode *clone() const { return new LabelNode( *this ); }
282
283        virtual void print( std::ostream &, int indent = 0) const;
284        virtual void printOneLine( std::ostream &, int indent = 0) const;
285
286        const std::list< std::string > &get_labels() const { return labels; };
287        void append_label( std::string *label ) { labels.push_back( *label ); delete label; }
288  private:
289        std::list< std::string > labels;
290};
291
292class CommaExprNode : public CompositeExprNode {
293  public:
294        CommaExprNode();
295        CommaExprNode( ExpressionNode * );
296        CommaExprNode( ExpressionNode *, ExpressionNode * );
297        CommaExprNode( const CommaExprNode &other );
298
299        virtual CommaExprNode *add_to_list( ExpressionNode * );
300        virtual CommaExprNode *clone() const { return new CommaExprNode( *this ); }
301};
302
303class ForCtlExprNode : public ExpressionNode {
304  public:
305        ForCtlExprNode( ParseNode *, ExpressionNode *, ExpressionNode * ) throw ( SemanticError );
306        ForCtlExprNode( const ForCtlExprNode &other );
307        ~ForCtlExprNode();
308
309        StatementNode *get_init() const { return init; }
310        ExpressionNode *get_condition() const { return condition; }
311        ExpressionNode *get_change() const { return change; }
312
313        virtual ForCtlExprNode *clone() const { return new ForCtlExprNode( *this ); }
314        virtual Expression *build() const;
315
316        virtual void print( std::ostream &, int indent = 0 ) const;
317        virtual void printOneLine( std::ostream &, int indent = 0 ) const;
318  private:
319        StatementNode *init;
320        ExpressionNode *condition;
321        ExpressionNode *change;
322};
323
324class ValofExprNode : public ExpressionNode {
325  public:
326        ValofExprNode();
327        ValofExprNode( StatementNode *s = 0 );
328        ValofExprNode( const ValofExprNode &other );
329        ~ValofExprNode();
330
331        virtual ValofExprNode *clone() const { return new ValofExprNode( *this ); }
332
333        StatementNode *get_body() const { return body; }
334        void print( std::ostream &, int indent = 0 ) const;
335        void printOneLine( std::ostream &, int indent = 0 ) const;
336        Expression *build() const;
337
338  private:
339        StatementNode *body;
340};
341
342class TypeData;
343
344class DeclarationNode : public ParseNode {
345  public:
346        enum Qualifier { Const, Restrict, Volatile, Lvalue, Atomic };
347        enum StorageClass { Extern, Static, Auto, Register, Inline, Fortran, Noreturn, Threadlocal, NoStorageClass, };
348        enum BasicType { Char, Int, Float, Double, Void, Bool, Complex, Imaginary };
349        enum Modifier  { Signed, Unsigned, Short, Long };
350        enum Aggregate { Struct, Union, Trait };
351        enum TypeClass { Type, Dtype, Ftype };
352        enum BuiltinType { Valist };
353
354        static const char *storageName[];
355        static const char *qualifierName[];
356        static const char *basicTypeName[];
357        static const char *modifierName[];
358        static const char *aggregateName[];
359        static const char *typeClassName[];
360        static const char *builtinTypeName[];
361
362        static DeclarationNode *newFunction( std::string *name, DeclarationNode *ret, DeclarationNode *param, StatementNode *body, bool newStyle = false );
363        static DeclarationNode *newQualifier( Qualifier );
364        static DeclarationNode *newStorageClass( StorageClass );
365        static DeclarationNode *newBasicType( BasicType );
366        static DeclarationNode *newModifier( Modifier );
367        static DeclarationNode *newForall( DeclarationNode *);
368        static DeclarationNode *newFromTypedef( std::string *);
369        static DeclarationNode *newAggregate( Aggregate kind, const std::string *name, ExpressionNode *actuals, DeclarationNode *fields );
370        static DeclarationNode *newEnum( std::string *name, DeclarationNode *constants );
371        static DeclarationNode *newEnumConstant( std::string *name, ExpressionNode *constant );
372        static DeclarationNode *newName( std::string *);
373        static DeclarationNode *newFromTypeGen( std::string *, ExpressionNode *params );
374        static DeclarationNode *newTypeParam( TypeClass, std::string *);
375        static DeclarationNode *newTrait( std::string *name, DeclarationNode *params, DeclarationNode *asserts );
376        static DeclarationNode *newTraitUse( std::string *name, ExpressionNode *params );
377        static DeclarationNode *newTypeDecl( std::string *name, DeclarationNode *typeParams );
378        static DeclarationNode *newPointer( DeclarationNode *qualifiers );
379        static DeclarationNode *newArray( ExpressionNode *size, DeclarationNode *qualifiers, bool isStatic );
380        static DeclarationNode *newVarArray( DeclarationNode *qualifiers );
381        static DeclarationNode *newBitfield( ExpressionNode *size );
382        static DeclarationNode *newTuple( DeclarationNode *members );
383        static DeclarationNode *newTypeof( ExpressionNode *expr );
384        static DeclarationNode *newAttr( std::string *, ExpressionNode *expr );
385        static DeclarationNode *newAttr( std::string *, DeclarationNode *type );
386        static DeclarationNode *newBuiltinType( BuiltinType );
387
388        DeclarationNode *addQualifiers( DeclarationNode *);
389        DeclarationNode *copyStorageClasses( DeclarationNode *);
390        DeclarationNode *addType( DeclarationNode *);
391        DeclarationNode *addTypedef();
392        DeclarationNode *addAssertions( DeclarationNode *);
393        DeclarationNode *addName( std::string *);
394        DeclarationNode *addBitfield( ExpressionNode *size );
395        DeclarationNode *addVarArgs();
396        DeclarationNode *addFunctionBody( StatementNode *body );
397        DeclarationNode *addOldDeclList( DeclarationNode *list );
398        DeclarationNode *addPointer( DeclarationNode *qualifiers );
399        DeclarationNode *addArray( DeclarationNode *array );
400        DeclarationNode *addNewPointer( DeclarationNode *pointer );
401        DeclarationNode *addNewArray( DeclarationNode *array );
402        DeclarationNode *addParamList( DeclarationNode *list );
403        DeclarationNode *addIdList( DeclarationNode *list );       // old-style functions
404        DeclarationNode *addInitializer( InitializerNode *init );
405
406        DeclarationNode *cloneType( std::string *newName );
407        DeclarationNode *cloneType( DeclarationNode *existing );
408        DeclarationNode *cloneType( int ) { return cloneType( ( std::string *)0 ); }
409        DeclarationNode *cloneBaseType( std::string *newName );
410        DeclarationNode *cloneBaseType( DeclarationNode *newdecl );
411
412        DeclarationNode *appendList( DeclarationNode * );
413
414        DeclarationNode *clone() const;
415        void print( std::ostream &, int indent = 0 ) const;
416        void printList( std::ostream &, int indent = 0 ) const;
417
418        Declaration *build() const;
419        ::Type *buildType() const;
420
421        bool get_hasEllipsis() const;
422        const std::string &get_name() const { return name; }
423        LinkageSpec::Type get_linkage() const { return linkage; }
424        DeclarationNode *extractAggregate() const;
425        ExpressionNode *get_enumeratorValue() const { return enumeratorValue; }
426
427        DeclarationNode();
428        ~DeclarationNode();
429  private:
430        StorageClass buildStorageClass() const;
431        bool buildFuncSpecifier( StorageClass key ) const;
432
433        TypeData *type;
434        std::string name;
435        std::list< StorageClass > storageClasses;
436        std::list< std::string > attributes;
437        ExpressionNode *bitfieldWidth;
438        ExpressionNode *enumeratorValue;
439        InitializerNode *initializer;
440        bool hasEllipsis;
441        LinkageSpec::Type linkage;
442
443        static UniqueName anonymous;
444}; // DeclarationNode
445
446class StatementNode : public ParseNode {
447  public:
448        enum Type { Exp,   If,        Switch,  Case,    Default,  Choose,   Fallthru,
449                                While, Do,        For,
450                                Goto,  Continue,  Break,   Return,  Throw,
451                                Try,   Catch,     Finally, Asm,
452                                Decl
453        };
454
455        StatementNode();
456        StatementNode( const std::string *name );
457        StatementNode( Type t, ExpressionNode *control = 0, StatementNode *block = 0 );
458        StatementNode( Type t, std::string *target );
459        StatementNode( DeclarationNode *decl );
460
461        ~StatementNode();
462
463        static StatementNode *newCatchStmt( DeclarationNode *d = 0, StatementNode *s = 0, bool catchRestP = false );
464
465        StatementNode *set_block( StatementNode *b ) {  block = b; return this; }
466        StatementNode *get_block() const { return block; }
467
468        void set_control( ExpressionNode *c ) { control = c; }
469        ExpressionNode *get_control() const { return control; }
470
471        StatementNode::Type get_type() const { return type; }
472
473        StatementNode *add_label( const std::string * );
474        const std::list<std::string> &get_labels() const { return labels; }
475
476        void addDeclaration( DeclarationNode *newDecl ) { decl = newDecl; }
477        void setCatchRest( bool newVal ) { isCatchRest = newVal; }
478
479        std::string get_target() const;
480
481        StatementNode *add_controlexp( ExpressionNode * );
482        StatementNode *append_block( StatementNode * );
483        StatementNode *append_last_case( StatementNode * );
484
485        void print( std::ostream &, int indent = 0) const;
486        virtual StatementNode *clone() const;
487        virtual Statement *build() const;
488  private:
489        static const char *StType[];
490        Type type;
491        ExpressionNode *control;
492        StatementNode *block;
493        std::list<std::string> labels;
494        std::string *target;                            // target label for jump statements
495        DeclarationNode *decl;
496        bool isCatchRest;
497}; // StatementNode
498
499class CompoundStmtNode : public StatementNode {
500  public:
501        CompoundStmtNode();
502        CompoundStmtNode( const std::string * );
503        CompoundStmtNode( StatementNode * );
504        ~CompoundStmtNode();
505
506        void add_statement( StatementNode * );
507
508        void print( std::ostream &, int indent = 0 ) const;
509        virtual Statement *build() const;
510  private:
511        StatementNode *first, *last;
512};
513
514class AsmStmtNode : public StatementNode {
515  public:
516        AsmStmtNode( Type, bool voltile, ConstantNode *instruction, ExpressionNode *output = 0, ExpressionNode *input = 0, ConstantNode *clobber = 0, LabelNode *gotolabels = 0 );
517        ~AsmStmtNode();
518
519        void print( std::ostream &, int indent = 0 ) const;
520        Statement *build() const;
521  private:
522        bool voltile;
523        ConstantNode *instruction;
524        ExpressionNode *output, *input;
525        ConstantNode *clobber;
526        std::list<std::string> gotolabels;
527};
528
529class NullStmtNode : public CompoundStmtNode {
530  public:
531        Statement *build() const;
532        void print( std::ostream &, int indent = 0 ) const;
533};
534
535class InitializerNode : public ParseNode {
536  public:
537        InitializerNode( ExpressionNode *, bool aggrp = false,  ExpressionNode *des = 0 );
538        InitializerNode( InitializerNode *, bool aggrp = false, ExpressionNode *des = 0 );
539        ~InitializerNode();
540
541        ExpressionNode *get_expression() const { return expr; }
542
543        InitializerNode *set_designators( ExpressionNode *des ) { designator = des; return this; }
544        ExpressionNode *get_designators() const { return designator; }
545
546        InitializerNode *set_maybeConstructed( bool value ) { maybeConstructed = value; return this; }
547        bool get_maybeConstructed() const { return maybeConstructed; }
548
549        InitializerNode *next_init() const { return kids; }
550
551        void print( std::ostream &, int indent = 0 ) const;
552        void printOneLine( std::ostream & ) const;
553
554        virtual Initializer *build() const;
555  private:
556        ExpressionNode *expr;
557        bool aggregate;
558        ExpressionNode *designator; // may be list
559        InitializerNode *kids;
560        bool maybeConstructed;
561};
562
563class CompoundLiteralNode : public ExpressionNode {
564  public:
565        CompoundLiteralNode( DeclarationNode *type, InitializerNode *kids );
566        CompoundLiteralNode( const CompoundLiteralNode &type );
567        ~CompoundLiteralNode();
568
569        virtual CompoundLiteralNode *clone() const;
570
571        DeclarationNode *get_type() const { return type; }
572        CompoundLiteralNode *set_type( DeclarationNode *t ) { type = t; return this; }
573
574        InitializerNode *get_initializer() const { return kids; }
575        CompoundLiteralNode *set_initializer( InitializerNode *k ) { kids = k; return this; }
576
577        void print( std::ostream &, int indent = 0 ) const;
578        void printOneLine( std::ostream &, int indent = 0 ) const;
579
580        virtual Expression *build() const;
581  private:
582        DeclarationNode *type;
583        InitializerNode *kids;
584};
585
586template< typename SynTreeType, typename NodeType >
587void buildList( const NodeType *firstNode, std::list< SynTreeType *> &outputList ) {
588        SemanticError errors;
589        std::back_insert_iterator< std::list< SynTreeType *> > out( outputList );
590        const NodeType *cur = firstNode;
591
592        while ( cur ) {
593                try {
594//                      SynTreeType *result = dynamic_cast< SynTreeType *>( maybeBuild<typename std::result_of<decltype(&NodeType::build)(NodeType)>::type>( cur ) );
595                        SynTreeType *result = dynamic_cast< SynTreeType *>( maybeBuild<typename std::pointer_traits<decltype(cur->build())>::element_type>( cur ) );
596                        if ( result ) {
597                                *out++ = result;
598                        } else {
599                        } // if
600                } catch( SemanticError &e ) {
601                        errors.append( e );
602                } // try
603                cur = dynamic_cast< NodeType *>( cur->get_link() );
604        } // while
605        if ( ! errors.isEmpty() ) {
606                throw errors;
607        } // if
608}
609
610// in DeclarationNode.cc
611void buildList( const DeclarationNode *firstNode, std::list< Declaration * > &outputList );
612void buildList( const DeclarationNode *firstNode, std::list< DeclarationWithType *> &outputList );
613void buildTypeList( const DeclarationNode *firstNode, std::list< Type * > &outputList );
614
615// in ExpressionNode.cc
616ExpressionNode *flattenCommas( ExpressionNode *list );
617ExpressionNode *tupleContents( ExpressionNode *tuple );
618
619#endif // PARSENODE_H
620
621// Local Variables: //
622// tab-width: 4 //
623// mode: c++ //
624// compile-command: "make install" //
625// End: //
Note: See TracBrowser for help on using the repository browser.