source: src/Parser/ParseNode.h @ d9e2280

ADTaaron-thesisarm-ehast-experimentalcleanup-dtorsctordeferred_resndemanglerenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxmemorynew-astnew-ast-unique-exprnew-envno_listpersistent-indexerpthread-emulationqualifiedEnumresolv-newwith_gc
Last change on this file since d9e2280 was d9e2280, checked in by Peter A. Buhr <pabuhr@…>, 8 years ago

even more more refactoring of parser code

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