summaryrefslogtreecommitdiff
path: root/grammar
diff options
context:
space:
mode:
authorAdrian Thurston <thurston@colm.net>2019-12-01 09:38:20 -0800
committerAdrian Thurston <thurston@colm.net>2019-12-01 09:38:20 -0800
commitd71253d7fdb59464e5c094b5b091c87aa2a189d5 (patch)
tree90f71fa6cd6f3ad6d21bf56d47e077fb5b6f4516 /grammar
parent5a4407de2c4c03083f1c25b5c7fdb849cdc08a12 (diff)
downloadcolm-d71253d7fdb59464e5c094b5b091c87aa2a189d5.tar.gz
added C++ and Python grammars, taken from test suite
These both need to be updated and tested for code in the wild. They were originally developed to showcase colm features.
Diffstat (limited to 'grammar')
-rw-r--r--grammar/Makefile6
-rw-r--r--grammar/c++/.gitignore2
-rw-r--r--grammar/c++/Makefile7
-rw-r--r--grammar/c++/c++.lm2248
-rw-r--r--grammar/c++/expected74
-rw-r--r--grammar/c++/input.cc153
-rw-r--r--grammar/pcre/Makefile4
-rw-r--r--grammar/python/.gitignore2
-rw-r--r--grammar/python/Makefile7
-rw-r--r--grammar/python/expected137
-rw-r--r--grammar/python/input.py47
-rw-r--r--grammar/python/python.lm579
12 files changed, 3260 insertions, 6 deletions
diff --git a/grammar/Makefile b/grammar/Makefile
index 21a2603a..44ac4032 100644
--- a/grammar/Makefile
+++ b/grammar/Makefile
@@ -1,6 +1,4 @@
-SUBDIRS = "rust pcre dns"
+SUBDIRS = rust pcre dns c++ python
all: rust pcre dns
- for d in $(SUBDIRS); do cd $$d && $(MAKE); done
-
-
+ for d in $(SUBDIRS); do ( cd $$d && $(MAKE) ); done
diff --git a/grammar/c++/.gitignore b/grammar/c++/.gitignore
new file mode 100644
index 00000000..3c976527
--- /dev/null
+++ b/grammar/c++/.gitignore
@@ -0,0 +1,2 @@
+/c++.c
+/c++
diff --git a/grammar/c++/Makefile b/grammar/c++/Makefile
new file mode 100644
index 00000000..e7bfe8d5
--- /dev/null
+++ b/grammar/c++/Makefile
@@ -0,0 +1,7 @@
+COLM = ../../colm/colm
+RAGEL = ../../ragel/ragel
+
+all: c++
+
+c++: c++.lm
+ $(COLM) -o $@ $<
diff --git a/grammar/c++/c++.lm b/grammar/c++/c++.lm
new file mode 100644
index 00000000..6aa0a5c5
--- /dev/null
+++ b/grammar/c++/c++.lm
@@ -0,0 +1,2248 @@
+
+context lookup
+ alias list_lang_object
+ list<lang_object>
+
+ alias list_declaration_data
+ list<declaration_data>
+
+ alias list_declarator_data
+ list<declarator_data>
+
+ alias list_int
+ list<int>
+
+ alias map_list_lang_object
+ map<str, list_lang_object>
+
+ #
+ # Data types for global data.
+ #
+
+ # Language objects.
+ struct lang_object
+ typeId: int
+ name: str
+
+ # If the object is a typedef, this points to the real object.
+ typedefOf: lang_object
+
+ objectMap: map_list_lang_object
+ inherited: list_lang_object
+ lookupParent: lang_object
+ specializationOf: lang_object
+ end
+
+ # This structure is used to keep track of information necessary to make a
+ # declaration. While parsing a declaration it records the declaration's
+ # attributes.
+ struct declaration_data
+ isTypedef: int
+ isFriend: int
+ isTemplate: int
+
+ typeObj: lang_object
+ end
+
+ struct declarator_data
+ qualObj: lang_object
+ pdcScope: lang_object
+ lookupObj: lang_object
+ end
+
+ # Constants for language object types.
+ NamespaceType: int
+ ClassType: int
+ TemplateClassType: int
+ EnumType: int
+ IdType: int
+ TypedefType: int
+ TemplateIdType: int
+
+ #
+ # Global data declarations
+ #
+
+ # Object stacks.
+ curNamespace: list_lang_object
+ declNs: list_lang_object
+ lookupNs: list_lang_object
+ qualNs: list_lang_object
+ templateParamNs: list_lang_object
+
+ # Declaration, declarator data.
+ declarationData: list_declaration_data
+ declaratorData: list_declarator_data
+
+ # Template declarations
+ templDecl: list_int
+
+ # Root namespace object
+ rootNamespace: lang_object
+
+ #
+ # Identifier lookup.
+ #
+
+ # Lookup the token in the members of an object.
+ lang_object lookupInObject( obj: lang_object, name: str )
+ {
+ # LOG print( ' looking in ', obj->name, '\n' )
+
+ ol: list_lang_object = obj->objectMap->find( name )
+ if ol {
+ # LOG print( ' * found an object: ', ol.head, '\n' )
+ return ol->head
+ }
+
+ return nil
+ }
+
+ # Lookup in an object and all the objects beneath it in the inheritance
+ # tree.
+ lang_object lookupWithInheritance( obj: lang_object, name: str )
+ {
+ found: lang_object = lookupInObject( obj, name )
+ if found
+ return found
+
+ for inh: lang_object in obj->inherited {
+ # First check if the inherited object is the one we are after.
+ if inh->name == name && inh->typeId == ClassType {
+ # LOG print( ' * found a class name\n' )
+ return inh
+ }
+
+ # Otherwise look inside the inherited object.
+ found = lookupWithInheritance( inh, name )
+ if found
+ return found
+ }
+
+ return nil
+ }
+
+ lang_object unqualifiedLookup( name: str )
+ {
+ found: lang_object
+
+ # Start with the objects in the templateParamNs.
+ for Obj: lang_object in rev_list_iter( templateParamNs ) {
+ found = lookupWithInheritance( Obj, name )
+ if found
+ break
+ }
+
+ if !found {
+ # Iterator over the objects starting at the head of the lookup stack
+ # and going up through the lookup parents.
+ lookupIn: lang_object = lookupNs->tail
+ while lookupIn {
+ found = lookupWithInheritance( lookupIn, name )
+ if found
+ break
+ lookupIn = lookupIn->lookupParent
+ }
+ }
+
+ return found
+ }
+
+ # The C++ scanner.
+ lex
+ rl fract_const / digit* '.' digit+ | digit+ '.' /
+ rl exponent / [eE] [+\-]? digit+ /
+ rl float_suffix / [flFL] /
+
+ # Single and double literals.
+ token TK_SingleLit /( 'L'? "'" ( [^'\\\n] | '\\' any )* "'" )/
+ token TK_DoubleLit /( 'L'? '"' ( [^"\\\n] | '\\' any )* '"' )/
+
+ literal `extern `namespace `friend `typedef `auto `register
+ `static `mutable `inline `virtual `explicit `const
+ `volatile `restrict `class `struct `union `template
+ `private `protected `public `using `void `char
+ `wchar_t `bool `int `float `double `short `long
+ `signed `unsigned `enum `new `delete `operator
+ `typename `export `throw `try `catch `sizeof
+ `dynamic_cast `static_cast `reinterpret_cast `const_cast
+ `typeid `this `true `false `switch `case `default
+ `if `else `while `do `for `break `continue
+ `return `goto
+
+ # Extensions
+ literal `__typeof `__is_pod `__is_empty
+
+ literal `{ `} `; `, `= `( `) `: `& `* `[ `] `~ `+ `-
+ `/ `< `> `| `^ `% `! `? `.
+
+ literal `:: `== `!= `&& `|| `*= `/= `%= `+= `-= `&=
+ `^= `|= `++ `-- `-> `->* `.* `... `<<= `>>=
+
+ # Token translation targets.
+ def unknown_id [lookup_id]
+ def class_id [lookup_id]
+ def namespace_id [lookup_id]
+ def templ_class_id [lookup_id]
+ def enum_id [lookup_id]
+ def typedef_id [lookup_id]
+ def identifier [lookup_id]
+ def template_id [lookup_id]
+
+ # Identifiers
+ token lookup_id
+ obj: lang_object
+ qualObj: lang_object
+
+ /( [a-zA-Z_] [a-zA-Z0-9_]* )/
+ {
+ name: str = match_text
+ found: lang_object = nil
+ qualObj: lang_object = nil
+ if qualNs->tail {
+ # LOG print( 'qualified lookup of ', name, '\n' )
+
+ # Transfer the qualification to the token and reset it.
+ qualObj = qualNs->tail
+ qualNs->pop_tail()
+ qualNs->push_tail( nil )
+
+ # Lookup using the qualification.
+ found = lookupWithInheritance( qualObj, name )
+ }
+ else {
+ # No qualification, full search.
+ # LOG print( 'unqualified lookup of ', name, '\n' )
+ found = unqualifiedLookup( name )
+ }
+
+ # If no match, return an Unknown ID
+ id: int = typeid<unknown_id>
+ if found
+ id = found->typeId
+
+ LookupId: lookup_id = make_token( typeid<lookup_id>,
+ input->pull(match_length) )
+ LookupId.obj = found
+ LookupId.qualObj = qualObj
+
+ input->push( make_tree( id, LookupId ) )
+ }
+
+ # Floats.
+ token TK_Float /( fract_const exponent? float_suffix? |
+ digit+ exponent float_suffix? )/
+
+ # Integer decimal. Leading part buffered by float.
+ token TK_IntegerDecimal /( ( '0' | [1-9] [0-9]* ) [ulUL]{0,3} )/
+
+ # Integer octal. Leading part buffered by float.
+ token TK_IntegerOctal /( '0' [0-9]+ [ulUL]{0,2} )/
+
+ # Integer hex. Leading 0 buffered by float.
+ token TK_IntegerHex /( '0x' [0-9a-fA-F]+ [ulUL]{0,2} )/
+
+ # Preprocessor line.
+ ignore /'#' [^\n]* '\n'/
+
+ # Comments and whitespace.
+ ignore /( '/*' (any | '\n')* :>> '*/' )/
+ ignore /( '//' any* :> '\n' )/
+ ignore /( any - 33..126 )+/
+ end
+
+ #
+ # Support functions
+ #
+
+ typeId: int
+ name: str
+
+ # If the object is a typedef, this points to the real object.
+ typedefOf: lang_object
+
+ objectMap: map_list_lang_object
+ inherited: list_lang_object
+ lookupParent: lang_object
+ specializationOf: lang_object
+
+ lang_object createLangObject( typeId: int, name: str, lookupParent: lang_object )
+ {
+ Obj: lang_object = new lang_object()
+
+ Obj->typeId = typeId
+ Obj->name = name
+ Obj->typedefOf = nil
+ Obj->objectMap = new map_list_lang_object()
+ Obj->inherited = new list_lang_object()
+ Obj->lookupParent = lookupParent
+
+ return Obj
+ }
+
+ # Building the language object tree.
+ int insertObject( definedIn: lang_object, name: str, obj: lang_object )
+ {
+ ol: list_lang_object = definedIn->objectMap->find( name )
+ if !ol {
+ # Element not in the map already
+ ol = new list_lang_object()
+ definedIn->objectMap->insert( name, ol )
+ }
+ ol->push_tail( obj )
+ }
+
+ lang_object findClass( inObj: lang_object, lang_objectname: str )
+ {
+ List: list_lang_object = inObj->objectMap->find( name )
+ if List {
+ for obj: lang_object in List {
+ if obj->typeId == ClassType {
+ return obj
+ }
+ }
+ }
+ return nil
+ }
+
+ lang_object findTemplateClass( inObj: lang_object, name: str )
+ {
+ List: list_lang_object = inObj->objectMap->find( name )
+ if List {
+ for obj: lang_object in List {
+ if obj->typeId == TemplateClassType
+ return obj
+ }
+ }
+ return nil
+ }
+
+ def root_qual_opt
+ []
+ | [`::]
+
+ def nested_name_specifier_opt
+ [nested_name_specifier_opt qualifying_name `:: designated_qualifying_name `::]
+ | [nested_name_specifier_opt qualifying_name `::]
+ | []
+
+ def nested_name_specifier
+ [nested_name_specifier designated_qualifying_name `::]
+ | [nested_name_specifier qualifying_name `::]
+ | [qualifying_name `::]
+
+ def qualifying_name
+ [class_name]
+ {
+ qualNs->pop_tail()
+ qualNs->push_tail( r1.lookupId.obj )
+ }
+
+ | [namespace_id]
+ {
+ match r1 [Id: lookup_id]
+ qualNs->pop_tail()
+ qualNs->push_tail( Id.obj )
+ }
+
+ | [typedef_id]
+ {
+ match r1 [Id: lookup_id]
+ qualNs->pop_tail()
+ qualNs->push_tail( Id.obj->typedefOf )
+ }
+
+ def designated_qualifying_name
+ [`template any_id]
+ {
+ # FIXME: nulling qualNs is not the right thing to do here.
+ qualNs->pop_tail()
+ qualNs->push_tail( nil )
+ }
+
+ | [`template any_id
+ templ_arg_open template_argument_list_opt templ_arg_close]
+ {
+ # FIXME: nulling qualNs is not the right thing to do here.
+ qualNs->pop_tail()
+ qualNs->push_tail( nil )
+ }
+
+ #
+ # Id Expression
+ #
+
+ def id_expression
+ lookupId: lookup_id
+
+ [root_qual_opt nested_name_specifier_opt unknown_id]
+ {
+ lhs.lookupId = lookup_id in r3
+ }
+
+ | [root_qual_opt nested_name_specifier_opt identifier]
+ {
+ lhs.lookupId = lookup_id in r3
+ }
+
+ | [root_qual_opt nested_name_specifier_opt operator_function_id]
+ {
+ # Normally the token translation transfers the qualification. Since
+ # the operator_function_id does not end in a lookup we must do it ourselves.
+ qualObj: lang_object = qualNs->pop_tail()
+ qualNs->push_tail( nil )
+
+ lhs.lookupId = construct lookup_id ["x"]
+ lhs.lookupId.data = '<operator_function_id>'
+ lhs.lookupId.qualObj = qualObj
+ }
+
+ | [root_qual_opt nested_name_specifier_opt conversion_function_id]
+ {
+ # Normally the token translation transfers the qualification. Since
+ # the operator_function_id does not } in a lookup we must do it ourselves.
+ qualObj: lang_object = qualNs->pop_tail()
+ qualNs->push_tail( nil )
+
+ # Do we need qual reset here becauase operator_function_id does not do it?
+ lhs.lookupId = construct lookup_id ["x"]
+ lhs.lookupId.data = '<conversion_function_id>'
+ lhs.lookupId.qualObj = qualObj
+ }
+
+ | [root_qual_opt nested_name_specifier_opt `~ class_name]
+ {
+ lhs.lookupId = r4.lookupId
+ }
+
+ | [root_qual_opt nested_name_specifier_opt template_name]
+ {
+ lhs.lookupId = r3.lookupId
+ }
+
+ def template_name
+ lookupId: lookup_id
+
+ [template_id templ_arg_open template_argument_list_opt templ_arg_close]
+ {
+ lhs.lookupId = lookup_id in r1
+ }
+
+ | [template_id]
+ {
+ lhs.lookupId = lookup_id in r1
+ }
+
+
+ #
+ # Class Names
+ #
+
+ def class_name
+ lookupId: lookup_id
+
+ [class_id]
+ {
+ lhs.lookupId = lookup_id in r1
+ }
+
+ | [templ_class_id]
+ {
+ lhs.lookupId = lookup_id in r1
+ }
+
+ | [templ_class_id templ_arg_open template_argument_list_opt templ_arg_close]
+ {
+ # TODO: Look for a specialization.
+ lhs.lookupId = lookup_id in r1
+ }
+
+ def templ_arg_open
+ [`<]
+ {
+ qualNs->push_tail( nil )
+ }
+
+ def templ_arg_close
+ [`>]
+ {
+ qualNs->pop_tail()
+ }
+
+ def declaration
+ [block_declaration] commit
+ | [function_definition] commit
+ | [template_declaration] commit
+ | [explicit_instantiation] commit
+ | [explicit_specialization] commit
+ | [linkage_specification] commit
+ | [namespace_definition] commit
+
+ #
+ # Declarations
+ #
+
+ def block_declaration
+ [simple_declaration]
+ | [using_declaration]
+ | [using_directive]
+
+ def simple_declaration
+ [declaration_start simple_declaration_forms declaration_end `;]
+
+ # Ordering is important for optimization. The form with the optional
+ # decl_specifier_sing should go second.
+ def simple_declaration_forms
+ [decl_specifier_mult_seq_opt decl_specifier_sing
+ decl_specifier_mult_seq_opt init_declarator_list_opt]
+
+ | [decl_specifier_mult_seq_opt init_declarator_list_opt]
+
+ def declaration_start
+ []
+ {
+ # LOG print( 'opening new declaration_data with templDecl: ', templDecl.tail, '\n' )
+ DD: declaration_data = new declaration_data()
+ DD->isTypedef = 0
+ DD->isFriend = 0
+ DD->isTemplate = 0
+ declarationData->push_tail( DD )
+
+ # Transfer the template flag and reset it.
+ declarationData->tail->isTemplate = templDecl->tail
+ templDecl->push_tail( 0 )
+ }
+
+ def declaration_end
+ []
+ {
+ # LOG print( 'closing declaration_data\n' )
+ declarationData->pop_tail()
+ templDecl->pop_tail()
+ }
+
+ def decl_specifier_sing
+ [type_specifier_sing]
+ {
+ # Store the object type of the declaration (if any) for use
+ # by typedefs.
+ declarationData->tail->typeObj = r1.lookupId.obj
+ }
+
+ def type_specifier_seq
+ lookupId: lookup_id
+
+ [type_specifier_mult_seq_opt type_specifier_sing type_specifier_mult_seq_opt]
+ {
+ lhs.lookupId = r2.lookupId
+ }
+
+ def type_specifier_sing
+ lookupId: lookup_id
+
+ [simple_type_specifier]
+ {
+ lhs.lookupId = r1.lookupId
+ }
+
+ | [class_specifier]
+ {
+ lhs.lookupId = construct lookup_id ["x"]
+ lhs.lookupId.data = '<class_specifier>'
+ }
+
+ | [enum_specifier]
+ {
+ lhs.lookupId = construct lookup_id ["x"]
+ lhs.lookupId.data = '<enum_specifier>'
+ }
+
+ | [elaborated_type_specifier]
+ {
+ lhs.lookupId = construct lookup_id ["x"]
+ lhs.lookupId.data = '<elaborated_type_specifier>'
+ }
+
+ # Type specifier sequence without enum specifier or class specifier.
+ def necs_type_specifier_seq
+ [type_specifier_mult_seq_opt necs_type_specifier_sing type_specifier_mult_seq_opt]
+
+ # Type specifier singular without enum specifier or class specifier.
+ def necs_type_specifier_sing
+ [simple_type_specifier]
+ | [elaborated_type_specifier]
+
+ def type_specifier_mult_seq_opt
+ [type_specifier_mult_seq_opt type_specifier_mult]
+ | []
+
+ def type_specifier_mult_seq
+ [type_specifier_mult_seq type_specifier_mult]
+ | [type_specifier_mult]
+
+ def simple_type_specifier
+ lookupId: lookup_id
+
+ [simple_type_specifier_name]
+ {
+ lhs.lookupId = r1.lookupId
+ }
+
+ | [simple_type_specifier_kw_seq]
+ {
+ lhs.lookupId = construct lookup_id ["x"]
+ lhs.lookupId.data = '<simple_type_specifier_kw_seq>'
+ }
+
+ | [`typename root_qual_opt nested_name_specifier type_name]
+ {
+ lhs.lookupId = r4.lookupId
+ }
+
+ | [`typename root_qual_opt nested_name_specifier identifier]
+ {
+ lhs.lookupId = lookup_id in r4
+ }
+
+ | [`typename root_qual_opt nested_name_specifier unknown_id]
+ {
+ lhs.lookupId = lookup_id in r4
+ }
+
+ # Extension.
+ | [`__typeof `( expression `)]
+ {
+ lhs.lookupId = construct lookup_id ["x"]
+ lhs.lookupId.data = '<simple_type_specifier_kw_seq>'
+ }
+
+ def simple_type_specifier_name
+ lookupId: lookup_id
+
+ [qual_type_name]
+ {
+ lhs.lookupId = r1.lookupId
+ }
+
+ def simple_type_specifier_kw_seq
+ [simple_type_specifier_kw_seq simple_type_specifier_kw]
+ | [simple_type_specifier_kw]
+
+ def simple_type_specifier_kw
+ [`void]
+ | [`char]
+ | [`wchar_t]
+ | [`bool]
+ | [`int]
+ | [`float]
+ | [`double]
+ | [`short]
+ | [`long]
+ | [`signed]
+ | [`unsigned]
+
+ def qual_type_name
+ lookupId: lookup_id
+
+ [root_qual_opt nested_name_specifier_opt type_name]
+ {
+ lhs.lookupId = r3.lookupId
+ }
+
+ def type_name
+ lookupId: lookup_id
+
+ [class_name]
+ {
+ lhs.lookupId = r1.lookupId
+ }
+
+ | [enum_id]
+ {
+ lhs.lookupId = lookup_id in r1
+ }
+
+ | [typedef_id]
+ {
+ lhs.lookupId = lookup_id in r1
+ }
+
+ # NOTE: the typename case is moved to simple type specifier
+ # to take advantage of its conflict resolution.
+ def elaborated_type_specifier
+ [class_key nested_name_specifier_opt class_head_name]
+ {
+ Id: lookup_id = lookup_id in r3
+ name: str = Id.data
+
+ # Get the ns the class is declared in.
+ parentObj: lang_object = declNs->tail
+ if Id.qualObj
+ parentObj = Id.qualObj
+
+ # Look for the class in the given scope.
+ declaredClass: lang_object = findClass( parentObj, name )
+ if !declaredClass
+ declaredClass = findTemplateClass( parentObj, name )
+
+ if !declaredClass {
+ # LOG print( 'creating new class: ', name, '\n' )
+
+ # Class does not exist in the parent scope, create it.
+ nsType: int = declaredClassType()
+
+ declaredClass = createLangObject( nsType, name, lookupNs->tail )
+
+ # FIXME: handle friends. Make the class visible only if we are NOT
+ # in a friend declaration. The new class object is necessary to
+ # properly process the body of the class.
+ if declarationData->tail->isFriend == 0
+ insertObject( parentObj, name, declaredClass )
+ }
+ }
+
+ # TODO: Lookup type specialization.
+ | [class_key nested_name_specifier_opt templ_class_id
+ templ_arg_open template_argument_list_opt templ_arg_close]
+
+ | [`enum nested_name_specifier_opt enum_head_name]
+ {
+ # TODO: should look for existing enums of the same name.
+ Id: lookup_id = lookup_id in r3
+ # LOG print( 'creating enumeration ' Id.data '\n' )
+ enum: lang_object = createLangObject( EnumType, Id.data, lookupNs->tail )
+ insertObject( declNs->tail, Id.data, enum )
+ }
+
+ def decl_specifier_mult_seq_opt
+ [decl_specifier_mult_seq_opt decl_specifier_mult]
+ | []
+
+ def decl_specifier_mult_seq
+ [decl_specifier_mult_seq decl_specifier_mult]
+ | [decl_specifier_mult]
+
+ def decl_specifier_mult
+ [type_specifier_mult]
+ | [storage_class_specifier]
+ | [function_specifier]
+
+ | [`friend]
+ {
+ declarationData->tail->isFriend = 1
+ }
+
+ | [`typedef]
+ {
+ declarationData->tail->isTypedef = 1
+ }
+
+ def storage_class_specifier
+ [`auto]
+ | [`register]
+ | [`static]
+ | [`extern]
+ | [`mutable]
+
+ def function_specifier
+ [`inline]
+ | [`virtual]
+ | [`explicit]
+
+ def type_specifier_mult
+ [cv_qualifier]
+
+ def cv_qualifier
+ [`const]
+ | [`volatile]
+ | [`restrict]
+
+ def cv_qualifier_rep
+ [cv_qualifier_rep cv_qualifier]
+ | []
+
+ def namespace_definition
+ [named_namespace_definition]
+ | [unnamed_namespace_definition]
+
+ def named_namespace_definition
+ [original_namespace_definition]
+ | [extension_namespace_definition]
+
+ #
+ # Enumerations
+ #
+
+ def enum_specifier
+ [`enum nested_name_specifier_opt
+ enum_head_name `{ enumerator_list_opt `}]
+ {
+ # TODO: should look for existing enums of the same name.
+ Id: lookup_id = lookup_id in r3
+ # LOG print( 'creating enumeration ' Id.data '\n' )
+ enum: lang_object = createLangObject( EnumType, Id.data, lookupNs->tail )
+ insertObject( declNs->tail, Id.data, enum )
+ }
+
+ | [`enum `{ enumerator_list_opt `}]
+
+ def enum_head_name
+ [class_id]
+ | [templ_class_id]
+ | [namespace_id]
+ | [typedef_id]
+ | [enum_id]
+ | [identifier]
+ | [template_id]
+ | [unknown_id]
+
+ def enumerator_list_opt
+ [enumerator_list]
+ | [enumerator_list `,]
+ | []
+
+ def enumerator_list
+ [enumerator_list `, enumerator_definition]
+ | [enumerator_definition]
+
+ def enumerator_definition
+ [enumerator_id]
+ {
+ Id: lookup_id = lookup_id in r1
+ enumId: lang_object = createLangObject( IdType, Id.data, lookupNs->tail )
+ insertObject( declNs->tail, Id.data, enumId )
+ }
+
+ | [enumerator_id `= constant_expression]
+ {
+ Id: lookup_id = lookup_id in r1
+ enumId: lang_object = createLangObject( IdType, Id.data, lookupNs->tail )
+ insertObject( declNs->tail, Id.data, enumId )
+ }
+
+ def enumerator_id
+ [namespace_id]
+ | [typedef_id]
+ | [enum_id]
+ | [class_id]
+ | [templ_class_id]
+ | [template_id]
+ | [identifier]
+ | [unknown_id]
+
+ #
+ # Declarators
+ #
+
+ def init_declarator_list_opt
+ [init_declarator_list]
+ | []
+
+ def init_declarator_list
+ [init_declarator_list `, init_declarator]
+ | [init_declarator]
+
+ def init_declarator
+ [declarator initializer_opt]
+
+ def initializer_opt
+ [`= initializer_clause]
+ | [`( expression `)]
+ | []
+
+ def initializer_clause
+ [assignment_expression]
+ | [`{ initializer_list `}]
+ | [`{ initializer_list `, `}]
+ | [`{ `}]
+
+ def initializer_list
+ [initializer_list `, initializer_clause]
+ | [initializer_clause]
+
+ #
+ # Expressions
+ #
+
+ def expression
+ [expression `, assignment_expression]
+ | [assignment_expression]
+
+ def expression_opt
+ [expression]
+ | []
+
+ def constant_expression
+ [conditional_expression]
+
+ def constant_expression_opt
+ [constant_expression]
+ | []
+
+ def assignment_expression
+ [conditional_expression]
+ | [logical_or_expression assignment_op assignment_expression]
+ | [throw_expression]
+
+ def assignment_op
+ [`=]
+ | [`*=]
+ | [`/=]
+ | [`%=]
+ | [`+=]
+ | [`-=]
+ | [`>>=]
+ | [`<<=]
+ | [`&=]
+ | [`^=]
+ | [`|=]
+
+ def conditional_expression
+ [logical_or_expression]
+ | [logical_or_expression `? expression `: assignment_expression]
+
+ def logical_or_expression
+ [logical_or_expression `|| logical_and_expression]
+ | [logical_and_expression]
+
+ def logical_and_expression
+ [logical_and_expression `&& inclusive_or_expression]
+ | [inclusive_or_expression]
+
+ def inclusive_or_expression
+ [inclusive_or_expression `| exclusive_or_expression]
+ | [exclusive_or_expression]
+
+ def exclusive_or_expression
+ [exclusive_or_expression `^ and_expression]
+ | [and_expression]
+
+ def and_expression
+ [and_expression `& equality_expression]
+ | [equality_expression]
+
+ def equality_expression
+ [equality_expression `== relational_expression]
+ | [equality_expression `!= relational_expression]
+ | [relational_expression]
+
+ def relational_expression
+ [relational_expression `< shift_expression]
+ | [relational_expression `> shift_expression]
+ | [relational_expression lt_eq shift_expression]
+ | [relational_expression gt_eq shift_expression]
+ | [shift_expression]
+
+ def shift_expression
+ [shift_expression shift_left additive_expression]
+ | [shift_expression shift_right additive_expression]
+ | [additive_expression]
+
+ def additive_expression
+ [additive_expression `+ multiplicative_expression]
+ | [additive_expression `- multiplicative_expression]
+ | [multiplicative_expression]
+
+ def multiplicative_expression
+ [multiplicative_expression `* pm_expression]
+ | [multiplicative_expression `/ pm_expression]
+ | [multiplicative_expression `% pm_expression]
+ | [pm_expression]
+
+ def pm_expression
+ [pm_expression `->* cast_expression]
+ | [pm_expression `.* cast_expression]
+ | [cast_expression]
+
+ def cast_expression
+ [unary_expression]
+ | [`( type_id `) cast_expression]
+
+ def delete_expression
+ [root_qual_opt `delete cast_expression]
+ | [root_qual_opt `delete `[ `] cast_expression]
+
+ def new_initializer_opt
+ [new_initializer]
+ | []
+
+ def new_initializer
+ [`( expression_opt `)]
+
+ def direct_new_declarator
+ [`[ expression `]]
+ | [direct_new_declarator `[ constant_expression `]]
+
+ def new_declarator_opt
+ [new_declarator]
+ | []
+
+ def new_declarator
+ [direct_new_declarator]
+ | [ptr_operator_seq direct_new_declarator]
+ | [ptr_operator_seq]
+
+ def new_type_id
+ [necs_type_specifier_seq new_declarator_opt]
+
+ def new_placement
+ [`( expression `)]
+
+ def new_expression
+ [root_qual_opt `new new_type_id new_initializer_opt]
+ | [root_qual_opt `new new_placement new_type_id new_initializer_opt]
+ | [root_qual_opt `new `( type_id `) new_initializer_opt]
+ | [root_qual_opt `new new_placement `( type_id `) new_initializer_opt]
+
+ def unary_operator
+ [`*]
+ | [`&]
+ | [`+]
+ | [`-]
+ | [`!]
+ | [`~]
+
+ def unary_expression
+ [postfix_expression]
+ | [`++ cast_expression]
+ | [`-- cast_expression]
+ | [unary_operator cast_expression]
+ | [`sizeof `( type_id `)]
+ | [`sizeof unary_expression]
+ | [new_expression]
+ | [delete_expression]
+
+ def function_style_type_conv
+ [simple_type_specifier]
+
+
+ def postfix_expression
+ [primary_expression]
+ | [postfix_expression `[ expression `]]
+ | [postfix_expression `( expression_opt `)]
+ | [function_style_type_conv `( expression_opt `)]
+ | [member_request_expr dot_arrow id_expression]
+ | [member_request_expr dot_arrow pseudo_destructor_call]
+ | [postfix_expression `++]
+ | [postfix_expression `--]
+ | [`dynamic_cast templ_arg_open type_id templ_arg_close `( expression `)]
+ | [`static_cast templ_arg_open type_id templ_arg_close `( expression `)]
+ | [`reinterpret_cast templ_arg_open type_id templ_arg_close `( expression `)]
+ | [`const_cast templ_arg_open type_id templ_arg_close `( expression `)]
+ | [`typeid `( expression `)]
+ | [`typeid `( type_id `)]
+
+ def pseudo_destructor_call
+ [root_qual_opt nested_name_specifier_opt `~ pdc_type_name]
+
+ def primary_expression
+ [expr_lit]
+ | [`this]
+ | [`( expression `)]
+ | [id_expression]
+ # GNU extensions
+ | [`( `{ statement_rep `} `)]
+ | [`__is_pod `( type_id `)]
+ | [`__is_empty `( type_id `)]
+
+ def expr_lit
+ [TK_IntegerDecimal]
+ | [TK_IntegerOctal]
+ | [TK_IntegerHex]
+ | [TK_SingleLit]
+ | [TK_Float]
+ | [double_lit_list]
+ | [`true]
+ | [`false]
+
+ def double_lit_list
+ [TK_DoubleLit double_lit_list]
+ | [TK_DoubleLit]
+
+ def member_request_expr
+ [postfix_expression]
+ # {
+ # # FIXME: If no proper type is found, we must fail.
+ # # LOG print( 'setting member request scope\n' )
+ # # qualNs.set( $1->type != 0 ? $1->type->getObject() : 0 );
+ # }
+
+ def dot_arrow
+ [`->]
+ | [`.]
+
+ def pdc_type_name
+ [enum_id]
+ | [typedef_id]
+
+ #
+ # Statements
+ #
+
+ def statement_rep
+ [statement_rep statement]
+ | []
+
+ def statement
+ [declaration_statement]
+ | [labeled_statement]
+ | [expression_statement]
+ | [compound_statement]
+ | [selection_statement]
+ | [iteration_statement]
+ | [jump_statement]
+ | [try_block]
+
+ def labeled_statement
+ [label_id `: statement]
+ | [`case constant_expression `: statement]
+ | [`default `: statement]
+
+ def label_id
+ [unknown_id]
+ | [identifier]
+ | [class_id]
+ | [templ_class_id]
+ | [namespace_id]
+ | [typedef_id]
+ | [enum_id]
+ | [template_id]
+
+ def compound_statement
+ [`{ compound_begin statement_rep compound_end `}]
+
+ def compound_begin
+ []
+ {
+ newCompound: lang_object = createLangObject( 0,
+ '<compound_begin>', lookupNs->tail )
+ lookupNs->push_tail( newCompound )
+
+ declNs->push_tail( newCompound )
+ # LOG print( 'opening <compound>\n' )
+ }
+
+ def compound_end
+ []
+ {
+ lookupNs->pop_tail()
+ declNs->pop_tail()
+ # LOG print( 'closing <compound>\n' )
+ }
+
+ def selection_statement
+ [`if `( condition `) statement elseif_clauses else_clause]
+ | [`switch `( condition `) statement]
+
+ def elseif_clauses
+ [elseif_clauses `else `if `( condition `) statement]
+ | []
+
+ def else_clause
+ [`else statement]
+ | []
+
+ def iteration_statement
+ [`while `( condition `) statement]
+ | [`do statement `while `( expression `) `;]
+ | [`for `( for_init_statement condition_opt `; expression_opt `) statement]
+
+ def jump_statement
+ [`break `;]
+ | [`continue `;]
+ | [`return expression_opt `;]
+ | [`goto any_id `;]
+
+ def any_id
+ [unknown_id]
+ | [class_id]
+ | [namespace_id]
+ | [templ_class_id]
+ | [enum_id]
+ | [typedef_id]
+ | [identifier]
+ | [template_id]
+
+
+ def for_init_statement
+ [expression_statement]
+ | [stmt_block_declaration_forms `;]
+
+ def condition
+ [expression]
+ | [type_specifier_seq declarator `= assignment_expression]
+
+ def condition_opt
+ [condition]
+ | []
+
+ def expression_statement
+ [expression `;]
+ | [`;]
+
+ def declaration_statement
+ [stmt_block_declaration]
+
+ def stmt_block_declaration
+ [declaration_start stmt_block_declaration_forms declaration_end `;]
+ | [using_declaration]
+ | [using_directive]
+
+ def stmt_block_declaration_forms
+ [decl_specifier_mult_seq_opt decl_specifier_sing decl_specifier_mult_seq_opt
+ init_declarator_list_opt]
+ | [decl_specifier_mult_seq init_declarator_list_opt]
+
+ #
+ # Declarators
+ #
+
+ def declarator
+ lookupObj: lang_object
+
+ [ptr_operator_seq_opt declarator_id decl_array_or_param_rep declarator_end]
+ {
+ lhs.lookupObj = r4.lookupObj
+ }
+
+ | [ptr_operator_seq_opt `( sub_declarator `) decl_array_or_param_rep declarator_end]
+ {
+ lhs.lookupObj = r6.lookupObj
+ }
+
+ def sub_declarator
+ [ptr_operator_seq declarator_id decl_array_or_param_rep]
+ | [ptr_operator_seq `( sub_declarator `) decl_array_or_param_rep]
+ | [`( sub_declarator `) decl_array_or_param_rep]
+ | [declarator_id decl_array_or_param_rep]
+
+ def decl_array_or_param_rep
+ [decl_array_or_param_rep decl_array_or_param]
+ | []
+
+ def decl_array_or_param
+ [`[ constant_expression_opt `]]
+ | [`( parameter_declaration_clause `) cv_qualifier_rep exception_specification_opt]
+
+ def declarator_id
+ [declarator_id_forms]
+ {
+ name: str = r1.lookupId.data
+ qualObj: lang_object = r1.lookupId.qualObj
+
+ parentObj: lang_object = declNs->tail
+ if qualObj
+ parentObj = qualObj
+
+ # Decide if we are declaring a constructor/destructor.
+ isConstructor: bool
+ if parentObj == r1.lookupId.obj {
+ isConstructor = true
+ # LOG print( 'making declarator ' name ' a constructor/destructor\n' )
+ }
+
+ if parentObj->specializationOf &&
+ parentObj->specializationOf == r1.lookupId.obj
+ {
+ isConstructor = true
+ # LOG print( 'making declarator ' name ' a constructor/destructor\n' )
+ }
+
+ obj: lang_object = nil
+ if name && !isConstructor && declarationData->tail->isFriend == 0 {
+ if declarationData->tail->isTypedef {
+ obj = createLangObject( TypedefType, name, lookupNs->tail )
+ obj->typedefOf = declarationData->tail->typeObj
+ insertObject( parentObj, name, obj )
+
+ # LOG print( 'making declarator ' name ' a typedef\n' )
+ }
+ else {
+ if !qualObj {
+ if declarationData->tail->isTemplate {
+ # If in a template declaration and the name is not qualified then
+ # create the template id.
+ obj = createLangObject( TemplateIdType, name, lookupNs->tail )
+ #object->objType = declarationData.tail.type
+ insertObject( declNs->tail, name, obj )
+
+ # LOG print( 'making declarator ' name ' a template id\n' )
+ }
+ else {
+ obj = createLangObject( IdType, name, lookupNs->tail )
+ #object->objType = declarationData.tail().type;
+ insertObject( declNs->tail, name, obj )
+
+ # LOG print( 'making declarator ' name ' an id\n' )
+ }
+ }
+ }
+ }
+
+
+ DD: declarator_data = new declarator_data()
+ DD->qualObj = qualObj
+ DD->pdcScope = nil
+ DD->lookupObj = lookupNs->tail
+
+ declaratorData->push_tail( DD )
+
+ # If the declarator is qualified, push the qualification to the lookup
+ # stack. Also save it in the declarator data so it can be passed to a
+ # function body if needed.
+ if qualObj {
+ lookupNs->push_tail( qualObj )
+ declaratorData->tail->lookupObj = qualObj
+ }
+
+ # LOG print( 'reduced declarator_id: ' name '\n' )
+ }
+
+ # Undoes the setup done by declarator_id and pdc_start.
+ def declarator_end
+ lookupObj: lang_object
+
+ []
+ {
+ # Get the lookupObject from the scope and pass it up. If we are about to
+ # parse a function body it will be needed.
+ lhs.lookupObj = declaratorData->tail->lookupObj
+
+ pdcScope: lang_object = declaratorData->tail->pdcScope
+ qualObj: lang_object = declaratorData->tail->qualObj
+
+ declaratorData->pop_tail()
+
+ if pdcScope {
+ # LOG print( 'closing <pdc_scope>\n' )
+ lookupNs->pop_tail()
+ declNs->pop_tail()
+ }
+
+ if qualObj {
+ # LOG print( 'popping lookupNs\n' )
+ lookupNs->pop_tail()
+ }
+ }
+
+ def declarator_id_forms
+ lookupId: lookup_id
+
+ [id_expression]
+ {
+ lhs.lookupId = r1.lookupId
+ }
+
+ | [root_qual_opt nested_name_specifier_opt type_name]
+ {
+ lhs.lookupId = r3.lookupId
+ }
+
+ | [root_qual_opt nested_name_specifier_opt `~ class_id]
+ {
+ lhs.lookupId = lookup_id in r4
+ }
+
+ | [root_qual_opt nested_name_specifier_opt `~ templ_class_id]
+ {
+ lhs.lookupId = lookup_id in r4
+ }
+ | [root_qual_opt nested_name_specifier_opt `~ unknown_id]
+ {
+ lhs.lookupId = lookup_id in r4
+ }
+
+ def type_id
+ lookupId: lookup_id
+
+ [type_specifier_seq abstract_declarator_opt]
+ {
+ lhs.lookupId = r1.lookupId
+ }
+
+ def abstract_declarator_opt
+ [abstract_declarator]
+ | []
+
+ def abstract_declarator
+ [ptr_operator_seq abstract_noid abstract_decl_array_or_param_seq_opt declarator_end]
+ | [ptr_operator_seq `( sub_abstract_declarator `)
+ abstract_decl_array_or_param_seq_opt declarator_end]
+ | [abstract_noid abstract_decl_array_or_param_seq declarator_end]
+ | [`( sub_abstract_declarator `) abstract_decl_array_or_param_seq_opt declarator_end]
+
+ def sub_abstract_declarator
+ [ptr_operator_seq abstract_noid abstract_decl_array_or_param_seq_opt]
+
+ | [ptr_operator_seq `( sub_abstract_declarator `)
+ abstract_decl_array_or_param_seq_opt]
+
+ | [`( sub_abstract_declarator `) abstract_decl_array_or_param_seq_opt]
+
+ def abstract_noid
+ []
+ {
+ # Make scope for declarator.
+ DD: declarator_data = new declarator_data()
+ declaratorData->push_tail( DD )
+ }
+
+ def abstract_decl_array_or_param_seq_opt
+ [abstract_decl_array_or_param_seq_opt abstract_decl_array_or_param]
+ | []
+
+ def abstract_decl_array_or_param_seq
+ [abstract_decl_array_or_param_seq abstract_decl_array_or_param]
+ | [abstract_decl_array_or_param]
+
+ def abstract_decl_array_or_param
+ [`[ constant_expression_opt `]]
+ | [`( parameter_declaration_clause `) cv_qualifier_rep
+ exception_specification_opt]
+
+ def parameter_declaration_clause
+ [pdc_start parameter_declaration_list]
+ | [pdc_start parameter_declaration_list `...]
+ | [pdc_start parameter_declaration_list `, `...]
+ | [pdc_start `...]
+ | [pdc_start]
+
+ def pdc_start
+ []
+ {
+ if !declaratorData->tail->pdcScope {
+ # We are going to need a scope for the declarator.
+ pdcScope: lang_object = createLangObject( 0,
+ '<pdc_scope>', lookupNs->tail )
+
+ lookupNs->push_tail( pdcScope )
+ declNs->push_tail( pdcScope )
+
+ declaratorData->tail->pdcScope = pdcScope
+ declaratorData->tail->lookupObj = pdcScope
+ # LOG print( 'opening <pdc_scope>\n' )
+ }
+ }
+
+ def parameter_declaration_list
+ [parameter_declaration_list `, parameter_declaration]
+ | [parameter_declaration]
+
+ def parameter_declaration
+ [declaration_start parameter_declaration_forms declaration_end]
+
+ # Ordering the productions such that decl_specifier_sing is tried first is good
+ # for performance.
+ def parameter_declaration_forms
+ [decl_specifier_mult_seq_opt decl_specifier_sing decl_specifier_mult_seq_opt
+ param_maybe_declarator maybe_parameter_init]
+
+ | [decl_specifier_mult_seq param_maybe_declarator maybe_parameter_init]
+
+ def param_maybe_declarator
+ [abstract_declarator]
+ | [declarator]
+ | []
+
+ def maybe_parameter_init
+ [`= constant_expression]
+ | []
+
+ def ptr_operator
+ [`&]
+ | [root_qual_opt nested_name_specifier_opt `* cv_qualifier_rep]
+
+ def ptr_operator_seq
+ [ptr_operator_seq ptr_operator]
+ | [ptr_operator]
+
+ def ptr_operator_seq_opt
+ [ptr_operator_seq_opt ptr_operator]
+ | []
+
+ #
+ # Functions
+ #
+
+ def function_definition
+ [function_def_declaration ctor_initializer_opt function_body function_def_end]
+
+ def function_def_declaration
+ [declaration_start function_def_declaration_forms declaration_end]
+
+ def function_def_declaration_forms
+ [decl_specifier_mult_seq_opt decl_specifier_sing
+ decl_specifier_mult_seq_opt function_def_declarator]
+ | [decl_specifier_mult_seq function_def_declarator]
+ | [function_def_declarator]
+
+ def function_def_declarator
+ [declarator]
+ {
+ # The lookupObj from the declarator is the deepest lookup object found
+ # while parsing the declarator. Make it visible in the function body.
+ # This could be the args, the qualObj, or the parent to the function.
+ lookupNs->push_tail( r1.lookupObj )
+ }
+
+ def function_def_end
+ []
+ {
+ # Pop the lookup object.
+ lookupNs->pop_tail()
+ }
+
+ def function_body
+ [function_body_begin `{ statement_rep function_body_end `}]
+
+ def function_body_begin
+ []
+ {
+ newFunctionBody: lang_object = createLangObject( 0,
+ '<function_body_begin>', lookupNs->tail )
+
+ lookupNs->push_tail( newFunctionBody )
+
+ declNs->push_tail( newFunctionBody )
+
+ templDecl->push_tail( 0 )
+ # LOG print( 'opening <function_body>\n' )
+ }
+
+ def function_body_end
+ []
+ {
+ # First undoes the function body begin work. Then undoes the setup in
+ # function_def_declarator.
+ declNs->pop_tail()
+ lookupNs->pop_tail()
+ templDecl->pop_tail()
+ # LOG print( 'closing <function_body>\n' )
+ }
+
+
+
+ #
+ # Classs
+ #
+
+ int declaredClassType()
+ {
+ if declarationData->tail->isTemplate {
+ return TemplateClassType
+ } else {
+ return ClassType
+ }
+ }
+
+ def class_specifier
+ [class_head base_clause_opt `{ class_member_rep class_body_end `}]
+ {
+ # FIXME: reparse not implemented yet
+ # FIXME FIXME: reparse is actually implemented now implemented
+ # # Visit class function bodies, but skip nested classes.
+ # for CFB: class_function_body in lhs {
+ # skipping class_specifier
+ #
+ # # Reparse the text of the class function body as a function body
+ # function_body FB = parse function_body[ $CFB ]
+ #
+ # # Replace the class function body with the parsed function body.
+ # CFB = cons class_function_body [FB.tree]
+ # }
+ }
+
+ def class_head
+ [class_key]
+ {
+ nsType: int = declaredClassType()
+
+ # LOG print( 'creating new anonymous class\n' )
+ newClass: lang_object = createLangObject( nsType,
+ '<anon_class>', lookupNs->tail )
+
+ lookupNs->push_tail( newClass )
+ declNs->push_tail( newClass )
+ }
+
+ | [class_key nested_name_specifier_opt class_head_name]
+ {
+ Id: lookup_id = lookup_id in r3
+ name: str = Id.data
+
+ # Get the ns the class is declared in.
+ parentObj: lang_object = declNs->tail
+ if Id.qualObj
+ parentObj = Id.qualObj
+
+ # Look for the class in the given scope.
+ declaredClass: lang_object = findClass( parentObj, name )
+ if !declaredClass
+ declaredClass = findTemplateClass( parentObj, name )
+
+ if !declaredClass {
+ # LOG print( 'creating new class: ' name '\n' )
+
+ # Class does not exist in the parent scope, create it.
+ nsType: int = declaredClassType()
+
+ declaredClass = createLangObject( nsType, name, lookupNs->tail )
+
+ # FIXME: handle friends. Make the class visible only if we are NOT
+ # in a friend declaration. The new class object is necessary to
+ # properly process the body of the class.
+ if declarationData->tail->isFriend == 0
+ insertObject( parentObj, name, declaredClass )
+ }
+
+ # Push the found/new class.
+ lookupNs->push_tail( declaredClass )
+ declNs->push_tail( declaredClass )
+ }
+
+ | [class_key nested_name_specifier_opt templ_class_id
+ templ_arg_open template_argument_list_opt templ_arg_close]
+ {
+ match r3 [Id: lookup_id]
+ id: str = Id.data
+ classObj: lang_object = Id.obj
+
+ # TODO: Try to find the specializaition in the template class object.
+ # TypeList typeList;
+ # makeTypeList( typeList $6->last );
+
+ declaredClass: lang_object
+ #declaredClass = classObj->findSpecExact( typeList );
+ if !declaredClass {
+ # LOG print( 'making new template specialization\n' )
+ nsType: int = declaredClassType()
+ declaredClass = createLangObject( nsType, id, lookupNs->tail )
+ # LOG print( 'declaredClass: ' declaredClass '\n' )
+ declaredClass->specializationOf = classObj
+ # $$->typeListMapEl = classObj->typeListMap.insert( typeList, declaredClass );
+ }
+
+ # Push the found/new class.
+ lookupNs->push_tail( declaredClass )
+ declNs->push_tail( declaredClass )
+ }
+
+ def class_body_end
+ []
+ {
+ # Pop the class ns.
+ lookupNs->pop_tail()
+ declNs->pop_tail()
+
+ # LOG print( 'closing off class\n' )
+ }
+
+ def class_head_name
+ [class_id]
+ | [templ_class_id]
+ | [namespace_id]
+ | [typedef_id]
+ | [enum_id]
+ | [unknown_id]
+ | [identifier]
+ | [template_id]
+
+ def class_key
+ [`class]
+ | [`struct]
+ | [`union]
+
+ def class_member_rep
+ [class_member_rep class_member]
+ | []
+
+ def class_member
+ [member_declaration]
+ | [access_specifier `:]
+
+ def member_declaration
+ [declaration_start member_declaration_forms declaration_end `;]
+ | [class_function_definition]
+ | [using_declaration]
+ | [template_declaration]
+
+ def class_function_definition
+ [function_def_declaration ctor_initializer_opt class_function_body function_def_end]
+
+ lex
+ token cfb_open /'{'/
+ token cfb_close /'}'/
+ token cfb_string /
+ "'" ( [^'\\\n] | '\\' any )* "'" |
+ '"' ( [^"\\\n] | '\\' any )* '"'/
+ token cfb_comment /
+ ( '/*' (any | '\n')* :>> '*/' ) |
+ ( '//' any* :> '\n' )/
+ token cfb_data /[^{}'"/]+ | '/'/
+ end
+
+ def cfb_item
+ [cfb_data]
+ | [cfb_string]
+ | [cfb_comment]
+ | [cfb_open cfb_item* cfb_close]
+
+ def cfb_conts
+ [cfb_item* cfb_close]
+
+
+
+ def class_function_body
+ # ['{' cfb_conts]
+ #| [function_body]
+ [function_body]
+
+ # Get better performance if the form with decl_specifier_sing comes first.
+ def member_declaration_forms
+ [decl_specifier_mult_seq_opt decl_specifier_sing
+ decl_specifier_mult_seq_opt member_declarator_list_opt]
+ | [decl_specifier_mult_seq_opt member_declarator_list_opt]
+
+ def member_declarator_list_opt
+ [member_declarator_list]
+ | []
+
+ def member_declarator_list
+ [member_declarator_list `, member_declarator]
+ | [member_declarator]
+
+ def member_declarator
+ [declarator]
+ | [declarator `= constant_expression]
+ | [declarator `: constant_expression]
+ | [`: constant_expression]
+
+ def access_specifier
+ [`private]
+ | [`protected]
+ | [`public]
+
+ def access_specifier_opt
+ [access_specifier]
+ | []
+
+ def using_declaration
+ [`using id_expression `;]
+ {
+ obj: lang_object = r2.lookupId.obj
+ if obj
+ insertObject( declNs->tail, obj->name, obj )
+ }
+
+ | [`using type_id `;]
+ {
+ obj: lang_object = r2.lookupId.obj
+ if obj
+ insertObject( declNs->tail, obj->name, obj )
+ }
+
+ def using_directive
+ [`using `namespace root_qual_opt nested_name_specifier_opt
+ namespace_id `;]
+ {
+ # This uses a simple, incomplete guard against cycles in the graph of
+ # using namespaces. A more sophisticated and complete guard would look
+ # for longer cycles as well. Note that even gcc 3.3.5 does not bother.
+ match r5 [Id: lookup_id]
+ usingObject: lang_object = Id.obj
+ inObject: lang_object = declNs->tail
+ if usingObject != inObject
+ inObject->inherited->push_tail( usingObject )
+ }
+
+
+ #
+ # Derived classes
+ #
+
+ def base_clause_opt
+ [base_clause]
+ | []
+
+ def base_clause
+ [`: base_specifier_list]
+
+ def base_specifier_list
+ [base_specifier_list `, base_specifier]
+ | [base_specifier]
+
+ int addBaseSpecifier( inObject: lang_object, inheritedObject: lang_object )
+ {
+ # Resolve typedefs.
+ if inheritedObject->typeId == TypedefType
+ inheritedObject = inheritedObject->typedefOf
+
+ inObject->inherited->push_tail( inheritedObject )
+ }
+
+ def base_specifier
+ [root_qual_opt nested_name_specifier_opt type_name]
+ {
+ addBaseSpecifier( declNs->tail, r3.lookupId.obj )
+ }
+
+ | [`virtual access_specifier_opt root_qual_opt nested_name_specifier_opt type_name]
+ {
+ addBaseSpecifier( declNs->tail, r5.lookupId.obj )
+ }
+
+ | [access_specifier virtual_opt root_qual_opt nested_name_specifier_opt type_name]
+ {
+ addBaseSpecifier( declNs->tail, r5.lookupId.obj )
+ }
+
+ def virtual_opt
+ [`virtual]
+ | []
+
+ #
+ # Special member functions
+ #
+
+ def conversion_function_id
+ [`operator conversion_type_id]
+
+ def conversion_type_id
+ [necs_type_specifier_seq ptr_operator_seq_opt]
+
+ def ctor_initializer_opt
+ [ctor_initializer]
+ | []
+
+ def ctor_initializer
+ [`: mem_initializer_list]
+
+ def mem_initializer_list
+ [mem_initializer_list `, mem_initializer]
+ | [mem_initializer]
+
+ def mem_initializer
+ [mem_initializer_id `( expression_opt `)]
+
+ def mem_initializer_id
+ [root_qual_opt nested_name_specifier_opt unknown_id]
+ | [root_qual_opt nested_name_specifier_opt identifier]
+ | [root_qual_opt nested_name_specifier_opt type_name]
+ | [root_qual_opt nested_name_specifier_opt template_name]
+
+
+ #
+ # Overloading
+ #
+ def operator_function_id
+ [`operator operator]
+
+ def operator
+ [`+] | [`-] | [`*] | [`/] | [`=] | [`<] | [`>] | [`&] | [`|] |
+ [`^] | [`%] | [`~] | [`!] | [`( `)] | [`[ `]] | [`new] |
+ [`delete] | [`->] | [`++] | [`--] | [`*=] | [`/=] | [`%=] |
+ [`+=] | [`-=] | [`>>=] | [`<<=] | [`&=] | [`^=] | [`|=] | [`==] |
+ [`!=] | [`&&] | [`||] | [lt_eq] | [gt_eq] | [shift_left] | [shift_right]
+
+ def lt_eq
+ [`< `=]
+ # try {
+ # if ( $2->leader != 0 ) {
+ # #ifdef LOG_REDUCE
+ # cerr << "rejecting less-than equals-to" << endl;
+ # #endif
+ # reject();
+ # }
+ # };
+
+ def gt_eq
+ [`> `=]
+ # try {
+ # if ( $2->leader != 0 ) {
+ # #ifdef LOG_REDUCE
+ # cerr << "rejecting greater-than equals-to" << endl;
+ # #endif
+ # reject();
+ # }
+ # };
+
+ def shift_left
+ [`< `<]
+ # try {
+ # if ( $2->leader != 0 ) {
+ # #ifdef LOG_REDUCE
+ # cerr << "rejecting shift left" << endl;
+ # #endif
+ # reject();
+ # }
+ # };
+
+ def shift_right
+ [`> `>]
+ # try {
+ # if ( $2->leader != 0 ) {
+ # #ifdef LOG_REDUCE
+ # cerr << "rejecting shift right" << endl;
+ # #endif
+ # reject();
+ # }
+ # };
+
+ #
+ # Templates
+ #
+
+ def template_declaration
+ [template_declaration_params declaration]
+ {
+ templDecl->pop_tail()
+ templateParamNs->pop_tail()
+ }
+
+ def template_declaration_params
+ [`template `< tpl_start template_parameter_list `>]
+ {
+ templDecl->push_tail( 1 )
+ }
+
+ | [`export `template `< tpl_start template_parameter_list `>]
+ {
+ templDecl->push_tail( 1 )
+ }
+
+ def tpl_start
+ []
+ {
+ # Create a new scope for the template parameters.
+ newTemplateParamScope: lang_object =
+ createLangObject( 0, '<tpl_start>', lookupNs->tail )
+
+ templateParamNs->push_tail( newTemplateParamScope )
+ }
+
+ def template_parameter_list
+ [template_parameter_list `, template_parameter]
+ | [template_parameter]
+
+ def template_parameter
+ [type_parameter]
+ | [template_parameter_declaration]
+
+ def template_parameter_declaration
+ [declaration_start template_parameter_declaration_forms declaration_end]
+
+ def template_parameter_declaration_forms
+ [decl_specifier_mult_seq param_maybe_declarator maybe_parameter_init]
+
+ | [temp_param_decl_specifier_sing decl_specifier_mult_seq_opt
+ param_maybe_declarator maybe_parameter_init]
+
+ | [decl_specifier_mult_seq temp_param_decl_specifier_sing
+ decl_specifier_mult_seq_opt param_maybe_declarator maybe_parameter_init]
+
+ def temp_param_decl_specifier_sing
+ [temp_param_type_specifier_sing]
+
+ # Template parameters cannot support elaborated type specifer or class specifier.
+ def temp_param_type_specifier_sing
+ [templ_simple_type_specifier]
+ | [enum_specifier]
+
+ def templ_simple_type_specifier
+ [simple_type_specifier_name]
+ | [simple_type_specifier_kw_seq]
+
+ def type_parameter
+ [`class type_param_id type_param_init_opt]
+ {
+ Id: lookup_id = lookup_id in r2
+ if Id {
+ # The lookup ns should be a template param scope.
+ newClass: lang_object =
+ createLangObject( ClassType, Id.data, lookupNs->tail )
+ insertObject( templateParamNs->tail, Id.data, newClass )
+ }
+ }
+
+ | [`typename type_param_id type_param_init_opt]
+ {
+ Id: lookup_id = lookup_id in r2
+ if Id {
+ # The lookup ns should be a template param scope.
+ newClass: lang_object =
+ createLangObject( ClassType, Id.data, lookupNs->tail )
+ insertObject( templateParamNs->tail, Id.data, newClass )
+ }
+ }
+
+ | [`template `< tpl_start template_parameter_list `>
+ `class type_param_id templ_type_param_init_opt]
+ {
+ Id: lookup_id = lookup_id in r7
+ if Id {
+ newClass: lang_object =
+ createLangObject( TemplateClassType, Id.data, lookupNs->tail )
+ insertObject( templateParamNs->tail, Id.data, newClass )
+ }
+ }
+
+ def templ_type_param_init_opt
+ [`= id_expression]
+ | []
+
+ def type_param_init_opt
+ [`= type_id]
+ | []
+
+ def type_param_id
+ [namespace_id]
+ | [typedef_id]
+ | [enum_id]
+ | [class_id]
+ | [templ_class_id]
+ | [identifier]
+ | [template_id]
+ | [unknown_id]
+ | []
+
+ def template_argument_list_opt
+ [template_argument_list]
+ | []
+
+ def template_argument_list
+ [template_argument_list `, template_argument]
+ | [template_argument]
+
+ def template_argument
+ [type_id]
+ | [assignment_expression]
+
+ def explicit_instantiation
+ [`template declaration]
+ | [declaration_start decl_specifier_mult_seq `template declaration declaration_end]
+
+ def explicit_specialization
+ [`template `< `> declaration]
+
+ ## Not sure what this one is about?
+ #explicit_specialization:
+ # declaration_start decl_specifier_mult_seq KW_Template '<' '>'
+ # declaration declaration_end;
+
+
+ #
+ # Original namespace definition
+ #
+
+ def original_namespace_definition
+ [orig_namespace_def_name `{ declaration* namespace_end `}]
+
+ def orig_namespace_def_name [`namespace unknown_id]
+ {
+ match r2 [Id: lookup_id]
+ nspace: lang_object = createLangObject(
+ NamespaceType, Id.data, lookupNs->tail )
+
+ # Insert the new object into the dictionary of the parent.
+ insertObject( curNamespace->tail, Id.data, nspace )
+
+ # Push the namespace
+ curNamespace->push_tail( nspace )
+ declNs->push_tail( nspace )
+ lookupNs->push_tail( nspace )
+
+ # LOG print( 'created original namespace: ' Id.data '\n' )
+ }
+
+ def namespace_end []
+ {
+ # Pop the namespace.
+ curNamespace->pop_tail()
+ declNs->pop_tail()
+ lookupNs->pop_tail()
+
+ # LOG print( 'closed namespace\n' )
+ }
+
+ #
+ # Extension namespace definition
+ #
+
+ def extension_namespace_definition
+ [ext_namespace_def_name `{ declaration* namespace_end `}]
+
+ def ext_namespace_def_name [`namespace namespace_id]
+ {
+ match r2 [Id: lookup_id]
+ nspace: lang_object = Id.obj
+
+ # Push the namespace
+ curNamespace->push_tail( nspace )
+ declNs->push_tail( nspace )
+ lookupNs->push_tail( nspace )
+
+ # LOG print( 'found extended namespace: ' Id.data '\n' )
+ }
+
+ #
+ # Unnamed namespace definition
+ #
+ def unnamed_namespace_definition
+ [unnamed_namespace_def_name `{ declaration* namespace_end `}]
+
+ def unnamed_namespace_def_name [`namespace]
+ {
+ nspace: lang_object = createLangObject(
+ NamespaceType, '<unnamed_namespace>',
+ lookupNs->tail )
+
+ # Push the namespace
+ curNamespace->push_tail( nspace )
+ declNs->push_tail( nspace )
+ lookupNs->push_tail( nspace )
+
+ # LOG print( 'parsed unnamed namespace\n' )
+ }
+
+ #
+ # linkage_specification
+ #
+ def linkage_specification
+ [`extern TK_DoubleLit `{ declaration* `}]
+ | [`extern TK_DoubleLit declaration]
+
+ #
+ # Exception Handling.
+ #
+
+ def try_block
+ [`try compound_statement handler_seq]
+
+ def handler_seq
+ [handler_seq handler]
+ | [handler]
+
+ def handler
+ [`catch `( exception_declaration `) compound_statement]
+
+ def exception_declaration
+ [type_specifier_seq declarator]
+ | [type_specifier_seq abstract_declarator]
+ | [type_specifier_seq]
+ | [`...]
+
+ def throw_expression
+ [`throw assignment_expression]
+ | [`throw]
+
+ def exception_specification_opt
+ [exception_specification]
+ | []
+
+ def exception_specification
+ [`throw `( type_id_list_opt `)]
+
+ def type_id_list_opt
+ [type_id_list]
+ | []
+
+ def type_id_list
+ [type_id_list `, type_id]
+ | [type_id]
+
+ def start
+ [declaration*]
+
+ #
+ # Grammar done.
+ #
+
+ int printObject( indent: str, obj: lang_object )
+ {
+ print( indent, obj->name )
+
+ if obj->objectMap->length > 0
+ print( ' {\n' )
+
+ Map: map_list_lang_object = obj->objectMap
+ for List: list_lang_object in Map {
+ List2: list_lang_object = List
+ for Obj: lang_object in List2 {
+ printObject( indent + ' ', Obj )
+ }
+ }
+
+
+ if obj->objectMap->length > 0
+ print( indent, '}' )
+
+ print( '\n' )
+ }
+
+end # lookup
+
+#
+# Global data declarations
+#
+
+Lookup: lookup = new lookup()
+
+# Constants for language object types.
+Lookup->NamespaceType = typeid<lookup::namespace_id>
+Lookup->ClassType = typeid<lookup::class_id>
+Lookup->TemplateClassType = typeid<lookup::templ_class_id>
+Lookup->EnumType = typeid<lookup::enum_id>
+Lookup->IdType = typeid<lookup::identifier>
+Lookup->TypedefType = typeid<lookup::typedef_id>
+Lookup->TemplateIdType = typeid<lookup::template_id>
+
+
+# Object stacks.
+Lookup->curNamespace = new lookup::list_lang_object()
+Lookup->declNs = new lookup::list_lang_object()
+Lookup->lookupNs = new lookup::list_lang_object()
+Lookup->qualNs = new lookup::list_lang_object()
+Lookup->templateParamNs = new lookup::list_lang_object()
+
+# Declaration, declarator data.
+Lookup->declarationData = new lookup::list_declaration_data()
+Lookup->declaratorData = new lookup::list_declarator_data()
+
+# Template declarations
+Lookup->templDecl = new lookup::list_int()
+
+# Root namespace object
+Lookup->rootNamespace = lookup::createLangObject( Lookup->NamespaceType, '<root_namespace>', nil )
+
+# Initialize the namespace and declaration stacks with the root namespace
+Lookup->curNamespace->push_tail( Lookup->rootNamespace )
+Lookup->declNs->push_tail( Lookup->rootNamespace )
+Lookup->lookupNs->push_tail( Lookup->rootNamespace )
+
+# Start with no qualification (note variables are initialized to zero)
+Lookup->qualNs->push_tail( nil )
+
+Lookup->templDecl->push_tail( 0 )
+
+DD: lookup::declaration_data = new lookup::declaration_data()
+DD->isTypedef = 0
+DD->isFriend = 0
+DD->isTemplate = 0
+Lookup->declarationData->push_tail( DD )
+
+parse S: lookup::start( Lookup )[ stdin ]
+if ! S {
+ print( error )
+ exit( 1 )
+}
+
+print( '***** NAMSPACES *****\n' )
+lookup::printObject( '', Lookup->rootNamespace )
+print( '***** UNKNOWN DECLARATORS *****\n' )
+for DI: lookup::declarator_id in S {
+ if match DI
+ [lookup::root_qual_opt lookup::nested_name_specifier_opt lookup::`~ UID: lookup::unknown_id]
+ {
+ print( UID, '\n' )
+ }
+}
diff --git a/grammar/c++/expected b/grammar/c++/expected
new file mode 100644
index 00000000..4757e9e2
--- /dev/null
+++ b/grammar/c++/expected
@@ -0,0 +1,74 @@
+***** NAMSPACES *****
+<root_namespace> {
+ A {
+ B
+ }
+ B {
+ Find
+ }
+ C {
+ D
+ }
+ C
+ C
+ C
+ C {
+ j
+ }
+ C
+ C
+ C
+ C {
+ D
+ I
+ i
+ }
+ C {
+ find
+ }
+ C {
+ D
+ g
+ }
+ C {
+ D
+ f
+ }
+ D
+ E
+ E
+ T
+ Y {
+ Z
+ f
+ t
+ }
+ a
+ b
+ b
+ c
+ c
+ d
+ e
+ f
+ f
+ f
+ i
+ i
+ Int
+ ns1 {
+ sub1 {
+ A
+ }
+ sub2 {
+ B
+ }
+ }
+ ns2 {
+ C
+ i
+ }
+ function
+}
+***** UNKNOWN DECLARATORS *****
+C
diff --git a/grammar/c++/input.cc b/grammar/c++/input.cc
new file mode 100644
index 00000000..83d51071
--- /dev/null
+++ b/grammar/c++/input.cc
@@ -0,0 +1,153 @@
+namespace ns1
+{
+ namespace sub1 { class A {}; }
+ namespace sub2 { class B {}; }
+}
+
+namespace ns2
+{
+ int i = b;
+ class C
+ {
+ };
+
+ using namespace ns1;
+}
+
+ns2::sub1::A a;
+
+struct A
+{
+ struct B {};
+};
+
+struct C
+{
+ struct D : virtual public A {};
+};
+
+C::D::A d;
+
+C c;
+
+struct C
+{
+
+};
+
+enum E
+{
+ C,
+ b
+};
+
+E e;
+
+enum E
+{
+ C,
+ b
+};
+
+
+int i;
+class C
+{
+ int j;
+};
+
+class D
+{
+ int ~D();
+};
+
+int C::k;
+int C::~C;
+
+typedef int Int;
+
+class C {};
+void ~C( );
+void C::operator +( int i );
+
+int i;
+
+//void operator C( void k );
+
+class C
+{
+
+};
+
+int C::f( int i, int j( void v ) );
+class C
+{
+ class D {};
+
+ typedef C I;
+
+ I::D i;
+};
+
+C c;
+
+void function( int i, int j )
+{
+ function();
+}
+
+
+
+class B { class Find {}; };
+
+typedef B T;
+
+class C : public T
+{
+ Find find;
+};
+
+
+template <class X> struct Y
+{
+ X t;
+ void f();
+};
+
+template <class X> void Y<X>::f();
+template <class X> struct Y
+{
+ class Z {};
+};
+
+class Y<int>
+{
+ int i;
+};
+
+//void f( class C<int> i, int j );
+
+int f( int (*) [](), void );
+void f();
+class C
+{
+ class D {};
+ void g();
+};
+
+//typename C c;
+
+class C
+{
+ class D {};
+ int f();
+};
+
+int f()
+{
+}
+
+int C::f()
+{
+ D d;
+}
diff --git a/grammar/pcre/Makefile b/grammar/pcre/Makefile
index 6f895485..538d0220 100644
--- a/grammar/pcre/Makefile
+++ b/grammar/pcre/Makefile
@@ -7,5 +7,5 @@ pcre-colm: pcre.lm
$(COLM) -o $@ pcre.lm
pcre-ragel: pcre.rl $(RAGEL)
- $(RAGEL) -G2 pcre.rl
- gcc -g -Wall -o $@ pcre.c
+ $(RAGEL) -G2 -o pcre-ragel.c pcre.rl
+ gcc -g -Wall -o $@ pcre-ragel.c
diff --git a/grammar/python/.gitignore b/grammar/python/.gitignore
new file mode 100644
index 00000000..f62062c6
--- /dev/null
+++ b/grammar/python/.gitignore
@@ -0,0 +1,2 @@
+/python.c
+/python
diff --git a/grammar/python/Makefile b/grammar/python/Makefile
new file mode 100644
index 00000000..555b9d28
--- /dev/null
+++ b/grammar/python/Makefile
@@ -0,0 +1,7 @@
+COLM = ../../colm/colm
+RAGEL = ../../ragel/ragel
+
+all: python
+
+python: python.lm
+ $(COLM) -o $@ $<
diff --git a/grammar/python/expected b/grammar/python/expected
new file mode 100644
index 00000000..813aeb5b
--- /dev/null
+++ b/grammar/python/expected
@@ -0,0 +1,137 @@
+*** SUCCESS ***
+
+hello
+def dude():
+ yes
+ awesome;
+
+ # Here we have a comment
+ def realy_awesome(): # hi there
+ in_more
+
+ same_level
+ def one_liner(): first; second # both inside one_liner
+
+ back_down
+
+last_statement
+
+# dude, this is a comment
+ # some more
+hello
+if 1:
+ yes
+ awesome;
+
+ # Here we have a comment
+ if ('hello'): # hi there
+ in_more
+
+ same_level
+ if ['dude', 'dudess'].horsie(): first; second # both inside one_liner
+ 1
+
+ back_down
+
+last_statement
+
+hello = 1.1(20);
+
+# subscription
+a[1] = b[2];
+
+# simple slicing
+c[1:1] = d[2:2];
+
+# simple slicing
+e[1:1, 2:2] = f[3:3, 4:4];
+***
+STMT: hello
+STMT: def dude():
+ yes
+ awesome;
+
+ # Here we have a comment
+ def realy_awesome(): # hi there
+ in_more
+
+ same_level
+ def one_liner(): first; second # both inside one_liner
+
+ back_down
+
+STMT: yes
+STMT: awesome;
+
+ # Here we have a comment
+STMT: def realy_awesome(): # hi there
+ in_more
+
+ same_level
+ def one_liner(): first; second # both inside one_liner
+
+STMT: in_more
+
+STMT: same_level
+STMT: def one_liner(): first; second # both inside one_liner
+
+STMT: back_down
+
+STMT: last_statement
+
+# dude, this is a comment
+ # some more
+STMT: hello
+STMT: if 1:
+ yes
+ awesome;
+
+ # Here we have a comment
+ if ('hello'): # hi there
+ in_more
+
+ same_level
+ if ['dude', 'dudess'].horsie(): first; second # both inside one_liner
+ 1
+
+ back_down
+
+STMT: yes
+STMT: awesome;
+
+ # Here we have a comment
+STMT: if ('hello'): # hi there
+ in_more
+
+ same_level
+ if ['dude', 'dudess'].horsie(): first; second # both inside one_liner
+ 1
+
+STMT: in_more
+
+STMT: same_level
+STMT: if ['dude', 'dudess'].horsie(): first; second # both inside one_liner
+STMT: 1
+
+STMT: back_down
+
+STMT: last_statement
+
+STMT: hello = 1.1(20);
+
+# subscription
+STMT: a[1] = b[2];
+
+# simple slicing
+STMT: c[1:1] = d[2:2];
+
+# simple slicing
+STMT: e[1:1, 2:2] = f[3:3, 4:4];
+TARGET SUBSCRIPTION: [1]
+TARGET SIMPLE SLICING: [1:1]
+TARGET EXTENDED SLICING: [1:1, 2:2]
+PRIMARY SUBSCRIPTION: [2]
+PRIMARY SIMPLE SLICING: [2:2]
+PRIMARY EXTENDED SLICING: [3:3, 4:4]
+*** SUCCESS ***
+
diff --git a/grammar/python/input.py b/grammar/python/input.py
new file mode 100644
index 00000000..a6380068
--- /dev/null
+++ b/grammar/python/input.py
@@ -0,0 +1,47 @@
+# dude, this is a comment
+ # some more
+hello
+def dude():
+ yes
+ awesome;
+
+ # Here we have a comment
+ def realy_awesome(): # hi there
+ in_more
+
+ same_level
+ def one_liner(): first; second # both inside one_liner
+
+ back_down
+
+last_statement
+
+# dude, this is a comment
+ # some more
+hello
+if 1:
+ yes
+ awesome;
+
+ # Here we have a comment
+ if ('hello'): # hi there
+ in_more
+
+ same_level
+ if ['dude', 'dudess'].horsie(): first; second # both inside one_liner
+ 1
+
+ back_down
+
+last_statement
+
+hello = 1.1(20);
+
+# subscription
+a[1] = b[2];
+
+# simple slicing
+c[1:1] = d[2:2];
+
+# simple slicing
+e[1:1, 2:2] = f[3:3, 4:4];
diff --git a/grammar/python/python.lm b/grammar/python/python.lm
new file mode 100644
index 00000000..ac3c8071
--- /dev/null
+++ b/grammar/python/python.lm
@@ -0,0 +1,579 @@
+context generate
+ # Regular definitions
+ rl ident_char /[a-zA-Z_]/
+
+ # List used as a stack of indentations.
+ IndentStack: list<int>
+
+ # Has a newline been sent for this '\n' .. whitespace match.
+ newline_sent: int
+
+ # Tokens.
+ lex
+ # Python keywords.
+ literal `and `del `from `not `while `as `elif `global `or
+ `with `assert `else `if `pass `yield `break `except
+ `import `print `class `exec `in `raise `continue
+ `finally `is `return `def `for `lambda `try
+
+ # Identifiers
+ rl lowercase /'a'..'z'/
+ rl uppercase /'A'..'Z'/
+ rl letter /lowercase | uppercase/
+ token identifier /(letter|'_') (letter | digit | '_')*/
+
+ # Literals
+ rl escapeseq /'\\' any /
+ rl longstringchar /[^\\]/
+ rl shortstringchar_s /[^\\\n']/
+ rl shortstringchar_d /[^\\\n"]/
+ rl longstringitem /longstringchar | escapeseq/
+ rl shortstringitem_s /shortstringchar_s | escapeseq/
+ rl shortstringitem_d /shortstringchar_d | escapeseq/
+ rl longstring /"'''" longstringitem* :>> "'''" | '"""' longstringitem* :>> '"""'/
+ rl shortstring /"'" shortstringitem_s* "'" | '"' shortstringitem_d* '"'/
+ rl stringprefix /"r" | "u" | "ur" | "R" | "U" | "UR" | "Ur" | "uR"/
+ token stringliteral /stringprefix? (shortstring | longstring)/
+
+ # Integers
+ rl hexdigit /digit | 'a'..'f' | 'A'..'F'/
+ rl octdigit /'0'..'7'/
+ rl nonzerodigit /'1'..'9'/
+ rl hexinteger /'0' ('x' | 'X') hexdigit+/
+ rl octinteger /'0' octdigit+/
+ rl decimalinteger /nonzerodigit digit* | '0'/
+ token integer /decimalinteger | octinteger | hexinteger/
+ token longinteger /integer ('l' | 'L')/
+
+ # Floats.
+ rl exponent /('e' | 'E') ('+' | '-')? digit+/
+ rl fraction /'.' digit+/
+ rl intpart /digit+/
+ rl pointfloat /intpart? fraction | intpart '.'/
+ rl exponentfloat /(intpart | pointfloat) exponent/
+ token floatnumber /pointfloat | exponentfloat/
+
+ # Imaginaries.
+ token imagnumber /(floatnumber | intpart) ("j" | "J")/
+
+ # Operators.
+ literal `+ `- `* `** `/ `// `% `<< `>> `& `| `^
+ `~ `< `> `<= `>= `== `!= `<>
+
+ # Delimiters
+ literal `( `) `[ `] `{ `} `@ `, `: `. `` `= `;
+ `+= `-= `*= `/= `//= `%= `&= `|= `^= `>>= `<<=
+ `**=
+
+ literal `...
+
+ # In general whitespace is ignored.
+ ignore WS /' '+/
+
+ # Find and ignore entire blank lines.
+ token BLANK_LINE
+ / '\n' [ \t]* ('#' [^\n]*)? '\n' /
+ {
+ # Need to shorten to take off the newline.
+ # Turn it into ignore.
+ input->push_ignore( make_token( typeid<WS>, input->pull(match_length - 1) ) )
+ }
+
+ # Find and ignore comments.
+ token COMMENT
+ / '#' [^\n]* '\n' /
+ {
+ # Need to shorten to take off the newline. Turn it into ignore.
+ input->push_ignore( make_token( typeid<WS>, input->pull(match_length - 1) ) )
+ }
+
+ # These tokens are generated
+ token INDENT //
+ token DEDENT //
+ token NEWLINE //
+ ignore IND_WS //
+
+ token INDENTATION
+ /'\n' [ \t]*/
+ {
+ # We have squared up INDENTs and DEDENTs. Ignore the entire match.
+ input->push_ignore( make_token( typeid<WS>, input->pull(match_length) ) )
+
+ # We have already sent the newline, compute the indentation level.
+ data_length: int = match_length - 1
+
+ Top: int = IndentStack->top
+ if data_length > Top {
+ # The indentation level is more than the level on the top
+ # of the stack. This is an indent event. Send as an INDENT.
+ input->push( make_token( typeid<INDENT>, '' ) )
+
+ # Push to the stack as per python manual.
+ IndentStack->push( data_length )
+ } else {
+ while data_length < Top {
+ # The indentation level is less than the level on the top of
+ # the stack. Pop the level and send one dedent. This flow of
+ # control will execute until we find the right indentation level
+ # to match up with.
+ IndentStack->pop()
+
+ # Send as a DEDENT
+ input->push( make_token( typeid<DEDENT>, '' ) )
+
+ Top = IndentStack->top
+ }
+ }
+
+ # FIXME: if data.length is now > top of stack then error. This
+ # means the outdent does not match anything.
+
+ # First the newline.
+ input->push( make_token( typeid<NEWLINE>, '' ) )
+ }
+ end
+
+ # Blank lines or comment lines at the beginning of the file.
+ token LEADER / ( [ \t]* ('#' [^\n]*)? '\n' )* /
+
+ # Ordering productions for resolving ambiguities.
+ def O1 []
+ def O2 []
+
+ def start
+ [file_input]
+
+ def file_input
+ [file_input_forms*]
+
+ def file_input_forms
+ [statement]
+ | [NEWLINE]
+
+ def statement
+ [stmt_list NEWLINE]
+ | [compound_stmt]
+
+ def stmt_list
+ [simple_stmt another_stmt* opt_semi]
+
+ def another_stmt
+ [`; simple_stmt]
+
+ def opt_semi
+ [`;]
+ | []
+
+ def suite
+ [stmt_list NEWLINE]
+ | [NEWLINE INDENT statement_seq DEDENT]
+
+ def statement_seq
+ [statement_seq statement]
+ | [statement]
+
+ def compound_stmt
+ [if_stmt]
+ | [while_stmt]
+ | [for_stmt]
+ | [funcdef]
+
+ def if_stmt
+ [`if expression `: suite elif_part* opt_else_part]
+
+ def elif_part
+ [`elif expression `: suite]
+
+ def opt_else_part
+ [`else `: suite]
+ | []
+
+ def while_stmt
+ [`while expression `: suite opt_else_part]
+
+ def for_stmt
+ [`for target_list `in expression_list `: suite opt_else_part]
+
+ def funcdef
+ [`def funcname `( opt_parameter_list `) `: suite]
+
+ def funcname
+ [identifier]
+
+ def dotted_name
+ [dotted_name `. identifier]
+ | [identifier]
+
+ def opt_parameter_list
+ [parameter_list]
+ | []
+
+ def parameter_list
+ [defparameter_list defparameter opt_comma]
+
+ def defparameter_list
+ [defparameter_list defparameter `,]
+ | []
+
+ def defparameter
+ [parameter]
+ | [parameter `= expression]
+
+ def sublist
+ [sublist_pl opt_comma]
+
+ def sublist_pl
+ [sublist_pl `, parameter]
+ | [parameter]
+
+ def parameter
+ [identifier]
+ | [`( sublist `)]
+
+ def classname
+ [identifier]
+
+ def simple_stmt
+ [expression_stmt]
+ | [assignment_stmt]
+ | [print_stmt]
+
+ def expression_stmt
+ [expression_list]
+
+ def assignment_stmt
+ [target_equals_list expression_list]
+
+ def target_equals_list
+ [target_equals_list target_equals]
+ | [target_equals]
+
+ def target_equals
+ [target_list `=]
+
+ def target_list
+ [target_list_core opt_comma]
+
+ def target_list_core
+ [target_list_core `, target]
+ | [target]
+
+ def target
+ [target_atom target_ext_rep]
+
+ def target_atom
+ [identifier]
+ | [`( target_list `)]
+ | [`[ target_list `]]
+
+ def target_ext_rep
+ [target_ext target_ext_rep]
+ | []
+
+ def target_ext
+ [attributeref]
+ | [O1 subscription]
+ | [O2 slicing]
+
+ def print_stmt
+ [`print opt_expression_list]
+
+ def opt_expression_list
+ [expression_list]
+ | []
+
+ def expression_list
+ [expression_list_core opt_comma]
+
+ def expression_list_core
+ [expression_list_core `, expression]
+ | [expression]
+
+ def opt_comma
+ [`,]
+ | []
+
+ def expression
+ [or_test `if or_test `else test]
+ | [or_test]
+ | [lambda_form]
+
+ def or_test
+ [or_test `or and_test]
+ | [and_test]
+
+ def and_test
+ [and_test `and not_test]
+ | [not_test]
+
+ def not_test
+ [comparison]
+ | [`not not_test]
+
+ def lambda_form
+ [`lambda opt_parameter_list `: expression]
+
+ def test
+ [or_test]
+ | [lambda_form]
+
+ def comparison
+ [or_expr comparison_part*]
+
+ def comparison_part
+ [comp_operator or_expr]
+
+ def comp_operator
+ [`<] | [`>] | [`==] | [`>=] | [`<=] | [`<>] | [`!=] | [`is] |
+ [`is `not] | [`in] | [`not `in]
+
+ def or_expr
+ [primary]
+
+ def primary
+ [atom primary_ext_rep]
+
+ def atom
+ [identifier]
+ | [pyliteral]
+ | [enclosure]
+
+ def primary_ext_rep
+ [primary_ext primary_ext_rep]
+ | []
+
+ def primary_ext
+ [attributeref]
+ | [O1 subscription]
+ | [O2 slicing]
+ | [call]
+
+ def pyliteral
+ [stringliteral]
+ | [integer]
+ | [longinteger]
+ | [floatnumber]
+ | [imagnumber]
+
+ def enclosure
+ [parenth_form]
+ | [list_display]
+ | [generator_expression]
+ | [dict_display]
+ | [string_conversion]
+
+ def parenth_form
+ [`( opt_expression_list `)]
+
+ def list_display
+ [`[ opt_listmaker `]]
+
+ def opt_listmaker
+ [listmaker]
+ | []
+
+ def listmaker
+ [expression list_for]
+ | [expression listmaker_ext* opt_comma]
+
+ def listmaker_ext
+ [`, expression]
+
+ def opt_list_iter
+ [list_iter]
+ | []
+
+ def list_iter
+ [list_for]
+ | [list_if]
+
+ def list_if
+ [`if test opt_list_iter]
+
+ def list_for
+ [`for expression_list `in testlist opt_list_iter]
+
+ def testlist
+ [test testlist_ext* opt_comma]
+
+ def testlist_ext
+ [`, test ]
+
+ def generator_expression
+ [`( test genexpr_for `)]
+
+ def genexpr_for
+ [`for expression_list `in test opt_genexpr_iter]
+
+ def opt_genexpr_iter
+ [genexpr_iter]
+ | []
+
+ def genexpr_iter
+ [genexpr_for]
+ | [genexpr_if]
+
+ def genexpr_if
+ [`if test opt_genexpr_iter]
+
+ def dict_display
+ [`{ opt_key_datum_list `}]
+
+ def opt_key_datum_list
+ [key_datum_list]
+ | []
+
+ def key_datum_list
+ [key_datum key_datum_list_ext* opt_comma]
+
+ def key_datum_list_ext
+ [`, key_datum]
+
+ def key_datum
+ [expression `: expression]
+
+ def string_conversion
+ [`` expression_list ``]
+
+ def attributeref
+ [`. identifier]
+
+ def subscription
+ [`[ expression_list `]]
+
+ # The natural ordered choice does not suffice here. Must force it.
+
+ def slicing
+ [simple_slicing]
+ | [extended_slicing]
+
+ def simple_slicing
+ [`[ short_slice `]]
+
+ def extended_slicing
+ [`[ slice_list `]]
+
+ def slice_list
+ [slice_item slice_list_ext* opt_comma]
+
+ def slice_list_ext
+ [`, slice_item]
+
+ def slice_item
+ [expression]
+ | [proper_slice]
+ | [ellipsis]
+
+ def proper_slice
+ [short_slice]
+ | [long_slice]
+
+ def short_slice
+ [`:]
+ | [`: upper_bound]
+ | [lower_bound `:]
+ | [lower_bound `: upper_bound]
+
+ def long_slice
+ [short_slice `: stride]
+ | [short_slice `:]
+
+ def lower_bound
+ [expression]
+
+ def upper_bound
+ [expression]
+
+ def stride
+ [expression]
+
+ def ellipsis
+ [`...]
+
+ def call
+ [`( opt_argument_list `)]
+
+ def opt_argument_list
+ [argument_list opt_comma]
+ | []
+
+ def argument_list
+ [positional_arguments opt_comma_keyword_arguments]
+ | [keyword_arguments]
+
+ def positional_arguments
+ [positional_arguments `, expression]
+ | [expression]
+
+ def opt_comma_keyword_arguments
+ [`, keyword_arguments]
+ | []
+
+ def keyword_arguments
+ [keyword_arguments `, keyword_item]
+ | [keyword_item]
+
+ def keyword_item
+ [identifier `= expression]
+
+end # generate
+
+int print_stmts( S: generate::start )
+{
+ for Stmt: generate::statement in S
+ print[ 'STMT: ' ^Stmt '\n' ]
+}
+
+int print_target_subscriptions_and_slicings( Start: generate::start )
+{
+ for TI: generate::target_ext in Start {
+ if match TI [generate::subscription] {
+ print[ 'TARGET SUBSCRIPTION: ' ^TI '\n' ]
+ }
+
+ if match TI [generate::simple_slicing] {
+ print[ 'TARGET SIMPLE SLICING: ' ^TI '\n' ]
+ }
+
+ if match TI [generate::extended_slicing] {
+ print[ 'TARGET EXTENDED SLICING: ' ^TI '\n' ]
+ }
+ }
+
+}
+
+int print_primary_subscriptions_and_slicings( Start: generate::start )
+{
+ for PI: generate::primary_ext in Start {
+ if match PI [generate::subscription] {
+ print[ 'PRIMARY SUBSCRIPTION: ' ^PI '\n' ]
+ }
+
+ if match PI [generate::simple_slicing] {
+ print[ 'PRIMARY SIMPLE SLICING: ' ^PI '\n' ]
+ }
+
+ if match PI [generate::extended_slicing] {
+ print[ 'PRIMARY EXTENDED SLICING: ' ^PI '\n' ]
+ }
+ }
+}
+
+Generate: generate = new generate()
+
+# List used as a stack of indentations.
+Generate->IndentStack = new list<int>()
+Generate->IndentStack->push( 0 )
+
+# Has a newline been sent for this '\n' .. whitespace match.
+Generate->newline_sent = 0
+
+parse S: generate::start(Generate)[ stdin ]
+
+print[ '*** SUCCESS ***\n' ]
+print[ ^S '\n' ]
+print[ '***\n' ]
+print_stmts( S )
+print_target_subscriptions_and_slicings( S )
+print_primary_subscriptions_and_slicings( S )
+print( '*** SUCCESS ***\n' )