Index: src/Parser/DeclarationNode.cc
===================================================================
--- src/Parser/DeclarationNode.cc	(revision d3b5a14152cd2218ed5407cc453d51052bfba812)
+++ src/Parser/DeclarationNode.cc	(revision e319fc52866340c9ab388498d1f0e9aec5c25fc3)
@@ -1076,8 +1076,8 @@
 	if ( variable.tyClass != TypeDecl::NUMBER_OF_KINDS ) {
 		// otype is internally converted to dtype + otype parameters
-		static const TypeDecl::Kind kindMap[] = { TypeDecl::Dtype, TypeDecl::DStype, TypeDecl::Dtype, TypeDecl::Ftype, TypeDecl::Ttype, TypeDecl::Dtype };
+		static const TypeDecl::Kind kindMap[] = { TypeDecl::Dtype, TypeDecl::DStype, TypeDecl::Dtype, TypeDecl::Ftype, TypeDecl::Ttype, TypeDecl::Dimension };
 		static_assert( sizeof(kindMap) / sizeof(kindMap[0]) == TypeDecl::NUMBER_OF_KINDS, "DeclarationNode::build: kindMap is out of sync." );
 		assertf( variable.tyClass < sizeof(kindMap)/sizeof(kindMap[0]), "Variable's tyClass is out of bounds." );
-		TypeDecl * ret = new TypeDecl( *name, Type::StorageClasses(), nullptr, kindMap[ variable.tyClass ], variable.tyClass == TypeDecl::Otype || variable.tyClass == TypeDecl::ALtype, variable.initializer ? variable.initializer->buildType() : nullptr );
+		TypeDecl * ret = new TypeDecl( *name, Type::StorageClasses(), nullptr, kindMap[ variable.tyClass ], variable.tyClass == TypeDecl::Otype, variable.initializer ? variable.initializer->buildType() : nullptr );
 		buildList( variable.assertions, ret->get_assertions() );
 		return ret;
Index: src/Parser/ExpressionNode.cc
===================================================================
--- src/Parser/ExpressionNode.cc	(revision d3b5a14152cd2218ed5407cc453d51052bfba812)
+++ src/Parser/ExpressionNode.cc	(revision e319fc52866340c9ab388498d1f0e9aec5c25fc3)
@@ -509,4 +509,9 @@
 } // build_varref
 
+DimensionExpr * build_dimensionref( const string * name ) {
+	DimensionExpr * expr = new DimensionExpr( *name );
+	delete name;
+	return expr;
+} // build_varref
 // TODO: get rid of this and OperKinds and reuse code from OperatorTable
 static const char * OperName[] = {						// must harmonize with OperKinds
Index: src/Parser/ParseNode.h
===================================================================
--- src/Parser/ParseNode.h	(revision d3b5a14152cd2218ed5407cc453d51052bfba812)
+++ src/Parser/ParseNode.h	(revision e319fc52866340c9ab388498d1f0e9aec5c25fc3)
@@ -183,4 +183,5 @@
 
 NameExpr * build_varref( const std::string * name );
+DimensionExpr * build_dimensionref( const std::string * name );
 
 Expression * build_cast( DeclarationNode * decl_node, ExpressionNode * expr_node );
Index: src/Parser/TypedefTable.cc
===================================================================
--- src/Parser/TypedefTable.cc	(revision d3b5a14152cd2218ed5407cc453d51052bfba812)
+++ src/Parser/TypedefTable.cc	(revision e319fc52866340c9ab388498d1f0e9aec5c25fc3)
@@ -10,6 +10,6 @@
 // Created On       : Sat May 16 15:20:13 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Mar 15 20:56:47 2021
-// Update Count     : 260
+// Last Modified On : Wed May 19 08:30:14 2021
+// Update Count     : 262
 //
 
@@ -31,4 +31,5 @@
 	switch ( kind ) {
 	  case IDENTIFIER: return "identifier";
+	  case TYPEDIMname: return "typedim";
 	  case TYPEDEFname: return "typedef";
 	  case TYPEGENname: return "typegen";
Index: src/Parser/parser.yy
===================================================================
--- src/Parser/parser.yy	(revision d3b5a14152cd2218ed5407cc453d51052bfba812)
+++ src/Parser/parser.yy	(revision e319fc52866340c9ab388498d1f0e9aec5c25fc3)
@@ -10,6 +10,6 @@
 // Created On       : Sat Sep  1 20:22:55 2001
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Apr 26 18:41:54 2021
-// Update Count     : 4990
+// Last Modified On : Wed May 19 14:20:36 2021
+// Update Count     : 5022
 //
 
@@ -287,5 +287,5 @@
 
 // names and constants: lexer differentiates between identifier and typedef names
-%token<tok> IDENTIFIER		QUOTED_IDENTIFIER	TYPEDEFname		TYPEGENname
+%token<tok> IDENTIFIER		QUOTED_IDENTIFIER	TYPEDIMname		TYPEDEFname		TYPEGENname
 %token<tok> TIMEOUT			WOR					CATCH			RECOVER			CATCHRESUME		FIXUP		FINALLY		// CFA
 %token<tok> INTEGERconstant	CHARACTERconstant	STRINGliteral
@@ -586,4 +586,8 @@
 	| quasi_keyword
 		{ $$ = new ExpressionNode( build_varref( $1 ) ); }
+	| TYPEDIMname										// CFA, generic length argument
+		// { $$ = new ExpressionNode( new TypeExpr( maybeMoveBuildType( DeclarationNode::newFromTypedef( $1 ) ) ) ); }
+		// { $$ = new ExpressionNode( build_varref( $1 ) ); }
+		{ $$ = new ExpressionNode( build_dimensionref( $1 ) ); }
 	| tuple
 	| '(' comma_expression ')'
@@ -2535,6 +2539,6 @@
 	| '[' identifier_or_type_name ']'
 		{
-			typedefTable.addToScope( *$2, TYPEDEFname, "9" );
-			$$ = DeclarationNode::newTypeParam( TypeDecl::ALtype, $2 );
+			typedefTable.addToScope( *$2, TYPEDIMname, "9" );
+			$$ = DeclarationNode::newTypeParam( TypeDecl::Dimension, $2 );
 		}
 	// | type_specifier identifier_parameter_declarator
@@ -2590,10 +2594,8 @@
 		{ $$ = new ExpressionNode( new TypeExpr( maybeMoveBuildType( $1 ) ) ); }
 	| assignment_expression
-		{ SemanticError( yylloc, toString("Expression generic parameters are currently unimplemented: ", $1->build()) ); $$ = nullptr; }
 	| type_list ',' type
 		{ $$ = (ExpressionNode *)($1->set_last( new ExpressionNode( new TypeExpr( maybeMoveBuildType( $3 ) ) ) )); }
 	| type_list ',' assignment_expression
-		{ SemanticError( yylloc, toString("Expression generic parameters are currently unimplemented: ", $3->build()) ); $$ = nullptr; }
-		// { $$ = (ExpressionNode *)( $1->set_last( $3 )); }
+		{ $$ = (ExpressionNode *)( $1->set_last( $3 )); }
 	;
 
