diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 23ed339bcdccd214219f643b532a225cce0824d9..bab4133cffc0b84a9f704b625c24824c34f5e793 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -41,6 +41,7 @@ jobs:
           - "8.0"
           - "8.1"
           - "8.2"
+          - "8.3"
     steps:
       - name: "Checkout"
         uses: "actions/checkout@v3"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b7c05b245965ffcb41a4dc831d260fa1e85e16c5..5aa1986696c5b44e11e168f5dfb95acc6617485a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,21 @@
+Version 4.18.0 (2023-12-10)
+---------------------------
+
+### Added
+
+* Added methods `ParserFactory::createForNewestSupportedVersion()` and
+  `ParserFactory::createForHostVersion()` for forward-compatibility with PHP-Parser 5.0.
+
+### Fixed
+
+* Fixed missing name resolution of class constant types.
+* Fixed class members being dropped if an error is encountered while parsing a later class member
+  (when error recovery is enabeld).
+
+### Changed
+
+* The `grammar/` directory has been excluded from exported git archives.
+
 Version 4.17.1 (2023-08-13)
 ---------------------------
 
diff --git a/grammar/php5.y b/grammar/php5.y
index 77e4fb7ede2a4255198bdfbfce397d9fd02e3764..d7d62887829a79f23beff6b91ac601b5c144d379 100644
--- a/grammar/php5.y
+++ b/grammar/php5.y
@@ -469,7 +469,7 @@ static_var:
 ;
 
 class_statement_list_ex:
-      class_statement_list_ex class_statement               { if ($2 !== null) { push($1, $2); } }
+      class_statement_list_ex class_statement               { if ($2 !== null) { push($1, $2); } else { $$ = $1; } }
     | /* empty */                                           { init(); }
 ;
 
diff --git a/grammar/php7.y b/grammar/php7.y
index 1ef60bfe03e02b8f768056f4036e2ba46473f293..53d619477e5f8206519b4f92eaa0e4be23f44325 100644
--- a/grammar/php7.y
+++ b/grammar/php7.y
@@ -708,7 +708,7 @@ static_var:
 ;
 
 class_statement_list_ex:
-      class_statement_list_ex class_statement               { if ($2 !== null) { push($1, $2); } }
+      class_statement_list_ex class_statement               { if ($2 !== null) { push($1, $2); } else { $$ = $1; } }
     | /* empty */                                           { init(); }
 ;
 
diff --git a/lib/PhpParser/NodeVisitor/NameResolver.php b/lib/PhpParser/NodeVisitor/NameResolver.php
index d0e7de02f5814e459f03213877e825977ba941bc..83f3ea831c92df1f8bf9e8aea3279a4905962735 100644
--- a/lib/PhpParser/NodeVisitor/NameResolver.php
+++ b/lib/PhpParser/NodeVisitor/NameResolver.php
@@ -118,6 +118,9 @@ class NameResolver extends NodeVisitorAbstract
                 $this->addNamespacedName($const);
             }
         } else if ($node instanceof Stmt\ClassConst) {
+            if (null !== $node->type) {
+                $node->type = $this->resolveType($node->type);
+            }
             $this->resolveAttrGroups($node);
         } else if ($node instanceof Stmt\EnumCase) {
             $this->resolveAttrGroups($node);
diff --git a/lib/PhpParser/Parser/Php5.php b/lib/PhpParser/Parser/Php5.php
index a43067108b20dae24830ef02a35092f06a79f49a..59bd1e8cf535609cbb7def17406215d65d0bcd6b 100644
--- a/lib/PhpParser/Parser/Php5.php
+++ b/lib/PhpParser/Parser/Php5.php
@@ -1738,7 +1738,7 @@ class Php5 extends \PhpParser\ParserAbstract
                  $this->semValue = new Stmt\StaticVar($this->semStack[$stackPos-(3-1)], $this->semStack[$stackPos-(3-3)], $this->startAttributeStack[$stackPos-(3-1)] + $this->endAttributes);
             },
             259 => function ($stackPos) {
-                 if ($this->semStack[$stackPos-(2-2)] !== null) { $this->semStack[$stackPos-(2-1)][] = $this->semStack[$stackPos-(2-2)]; $this->semValue = $this->semStack[$stackPos-(2-1)]; }
+                 if ($this->semStack[$stackPos-(2-2)] !== null) { $this->semStack[$stackPos-(2-1)][] = $this->semStack[$stackPos-(2-2)]; $this->semValue = $this->semStack[$stackPos-(2-1)]; } else { $this->semValue = $this->semStack[$stackPos-(2-1)]; }
             },
             260 => function ($stackPos) {
                  $this->semValue = array();
diff --git a/lib/PhpParser/Parser/Php7.php b/lib/PhpParser/Parser/Php7.php
index fc895cb047ca18accbb8ac8297ea1b36b3562b55..6d2b4b0f9ca224f2026c86e50592ec3a65179506 100644
--- a/lib/PhpParser/Parser/Php7.php
+++ b/lib/PhpParser/Parser/Php7.php
@@ -2056,7 +2056,7 @@ class Php7 extends \PhpParser\ParserAbstract
                  $this->semValue = new Stmt\StaticVar($this->semStack[$stackPos-(3-1)], $this->semStack[$stackPos-(3-3)], $this->startAttributeStack[$stackPos-(3-1)] + $this->endAttributes);
             },
             340 => function ($stackPos) {
-                 if ($this->semStack[$stackPos-(2-2)] !== null) { $this->semStack[$stackPos-(2-1)][] = $this->semStack[$stackPos-(2-2)]; $this->semValue = $this->semStack[$stackPos-(2-1)]; }
+                 if ($this->semStack[$stackPos-(2-2)] !== null) { $this->semStack[$stackPos-(2-1)][] = $this->semStack[$stackPos-(2-2)]; $this->semValue = $this->semStack[$stackPos-(2-1)]; } else { $this->semValue = $this->semStack[$stackPos-(2-1)]; }
             },
             341 => function ($stackPos) {
                  $this->semValue = array();
diff --git a/lib/PhpParser/ParserFactory.php b/lib/PhpParser/ParserFactory.php
index f041e7ffe3adcc4181c6900b55061ed596f2786b..baba23bdb49f9f270c77b089612f4421b885021b 100644
--- a/lib/PhpParser/ParserFactory.php
+++ b/lib/PhpParser/ParserFactory.php
@@ -2,6 +2,9 @@
 
 namespace PhpParser;
 
+use PhpParser\Lexer\Emulative;
+use PhpParser\Parser\Php7;
+
 class ParserFactory
 {
     const PREFER_PHP7 = 1;
@@ -41,4 +44,33 @@ class ParserFactory
                 );
         }
     }
+
+    /**
+     * Create a parser targeting the newest version supported by this library. Code for older
+     * versions will be accepted if there have been no relevant backwards-compatibility breaks in
+     * PHP.
+     *
+     * All supported lexer attributes (comments, startLine, endLine, startTokenPos, endTokenPos,
+     * startFilePos, endFilePos) will be enabled.
+     */
+    public function createForNewestSupportedVersion(): Parser {
+        return new Php7(new Emulative($this->getLexerOptions()));
+    }
+
+    /**
+     * Create a parser targeting the host PHP version, that is the PHP version we're currently
+     * running on. This parser will not use any token emulation.
+     *
+     * All supported lexer attributes (comments, startLine, endLine, startTokenPos, endTokenPos,
+     * startFilePos, endFilePos) will be enabled.
+     */
+    public function createForHostVersion(): Parser {
+        return new Php7(new Lexer($this->getLexerOptions()));
+    }
+
+    private function getLexerOptions(): array {
+        return ['usedAttributes' => [
+            'comments', 'startLine', 'endLine', 'startTokenPos', 'endTokenPos', 'startFilePos', 'endFilePos',
+        ]];
+    }
 }
diff --git a/test/PhpParser/NodeVisitor/NameResolverTest.php b/test/PhpParser/NodeVisitor/NameResolverTest.php
index b5035ce3fe16ddf723c83c411577feaf6e1f2ff4..3b1e920765d8e25784ab386621f143d37ffcde0e 100644
--- a/test/PhpParser/NodeVisitor/NameResolverTest.php
+++ b/test/PhpParser/NodeVisitor/NameResolverTest.php
@@ -189,7 +189,7 @@ class A extends B implements C, D {
         E::h as i;
         E::j insteadof F, G;
     }
-    
+
     #[X]
     public float $php = 7.4;
     public ?Foo $person;
@@ -198,6 +198,10 @@ class A extends B implements C, D {
 
     #[X]
     const C = 1;
+    
+    public const X A = X::Bar;
+    public const X\Foo B = X\Foo::Bar;
+    public const \X\Foo C = \X\Foo::Bar;
 }
 
 #[X]
@@ -263,6 +267,9 @@ class A extends \NS\B implements \NS\C, \NS\D
     public \NS\A|\NS\B|int $prop;
     #[\NS\X]
     const C = 1;
+    public const \NS\X A = \NS\X::Bar;
+    public const \NS\X\Foo B = \NS\X\Foo::Bar;
+    public const \X\Foo C = \X\Foo::Bar;
 }
 #[\NS\X]
 interface A extends \NS\C, \NS\D
diff --git a/test/PhpParser/ParserFactoryTest.php b/test/PhpParser/ParserFactoryTest.php
index d50981f2a1297d425ebf704600d35158bcae678c..fbdc83ae933008432fff2af31df6a9dc9e5e8a10 100644
--- a/test/PhpParser/ParserFactoryTest.php
+++ b/test/PhpParser/ParserFactoryTest.php
@@ -5,6 +5,8 @@ namespace PhpParser;
 /* This test is very weak, because PHPUnit's assertEquals assertion is way too slow dealing with the
  * large objects involved here. So we just do some basic instanceof tests instead. */
 
+use PhpParser\Node\Stmt\Echo_;
+
 class ParserFactoryTest extends \PHPUnit\Framework\TestCase
 {
     /** @dataProvider provideTestCreate */
@@ -33,4 +35,26 @@ class ParserFactoryTest extends \PHPUnit\Framework\TestCase
             ]
         ];
     }
+
+    /** @dataProvider provideTestLexerAttributes */
+    public function testLexerAttributes(Parser $parser) {
+        $stmts = $parser->parse("<?php /* Bar */ echo 'Foo';");
+        $stmt = $stmts[0];
+        $this->assertInstanceOf(Echo_::class, $stmt);
+        $this->assertCount(1, $stmt->getComments());
+        $this->assertSame(1, $stmt->getStartLine());
+        $this->assertSame(1, $stmt->getEndLine());
+        $this->assertSame(3, $stmt->getStartTokenPos());
+        $this->assertSame(6, $stmt->getEndTokenPos());
+        $this->assertSame(16, $stmt->getStartFilePos());
+        $this->assertSame(26, $stmt->getEndFilePos());
+    }
+
+    public function provideTestLexerAttributes() {
+        $factory = new ParserFactory();
+        return [
+            [$factory->createForHostVersion()],
+            [$factory->createForNewestSupportedVersion()],
+        ];
+    }
 }
diff --git a/test/code/parser/errorHandling/recovery.test b/test/code/parser/errorHandling/recovery.test
index c86d269f62f7b4bc9071f7d28725565aefb65212..f0ef5b4bd04d1785993bb7e9382e24c0cb265632 100644
--- a/test/code/parser/errorHandling/recovery.test
+++ b/test/code/parser/errorHandling/recovery.test
@@ -900,12 +900,13 @@ array(
 <?php
 
 class Foo {
+    public $bar1;
     publi $foo;
     public $bar;
 }
 -----
 !!php7
-Syntax error, unexpected T_STRING from 4:5 to 4:9
+Syntax error, unexpected T_STRING from 5:5 to 5:9
 array(
     0: Stmt_Class(
         attrGroups: array(
@@ -919,6 +920,20 @@ array(
         )
         stmts: array(
             0: Stmt_Property(
+                attrGroups: array(
+                )
+                flags: MODIFIER_PUBLIC (1)
+                type: null
+                props: array(
+                    0: Stmt_PropertyProperty(
+                        name: VarLikeIdentifier(
+                            name: bar1
+                        )
+                        default: null
+                    )
+                )
+            )
+            1: Stmt_Property(
                 attrGroups: array(
                 )
                 flags: MODIFIER_PUBLIC (1)
@@ -1523,4 +1538,4 @@ array(
             )
         )
     )
-)
\ No newline at end of file
+)