Skip to content

Commit 10a33c3

Browse files
committed
Add fortran-parser crate with recursive descent parser
- Implement recursive descent parser for FORTRAN programs - Parse program units: PROGRAM, SUBROUTINE, FUNCTION, MODULE - Parse declarations: variable declarations, type specs, attributes - Parse statements: IF, DO, READ, WRITE, PRINT, RETURN, STOP, etc. - Parse expressions: arithmetic, logical, comparison, function calls - Error handling with location information - Basic example demonstrating usage - Add README documentation
1 parent e0ae506 commit 10a33c3

File tree

7 files changed

+1253
-1
lines changed

7 files changed

+1253
-1
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[workspace]
22
members = ["fortran-ast",
3-
"fortran-lexer",
3+
"fortran-lexer", "fortran-parser",
44
]
55
resolver = "2"
66

fortran-parser/Cargo.toml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[package]
2+
name = "fortran-parser"
3+
version.workspace = true
4+
authors.workspace = true
5+
license.workspace = true
6+
repository.workspace = true
7+
edition.workspace = true
8+
description = "Recursive descent parser for FORTRAN source code"
9+
keywords = ["fortran", "parser", "compiler", "ast"]
10+
categories = ["parsing", "development-tools"]
11+
12+
[dependencies]
13+
fortran-lexer = { path = "../fortran-lexer" }
14+
fortran-ast = { path = "../fortran-ast" }

fortran-parser/README.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# fortran-parser
2+
3+
Recursive descent parser for FORTRAN source code that converts tokens into an Abstract Syntax Tree (AST).
4+
5+
## Features
6+
7+
- ✅ Parses FORTRAN program units (PROGRAM, SUBROUTINE, FUNCTION, MODULE)
8+
- ✅ Parses declarations (variable declarations, type specifications, attributes)
9+
- ✅ Parses executable statements (IF, DO, READ, WRITE, PRINT, etc.)
10+
- ✅ Parses expressions (arithmetic, logical, comparison, function calls)
11+
- ✅ Error reporting with location information
12+
- ✅ Handles whitespace and comments gracefully
13+
14+
## Usage
15+
16+
```rust
17+
use fortran_parser::parse;
18+
19+
let source = r#"
20+
program hello
21+
implicit none
22+
integer :: i
23+
print *, 'Hello, World!'
24+
end program hello
25+
"#;
26+
27+
let program = parse(source)?;
28+
println!("Parsed: {:?}", program);
29+
```
30+
31+
## Examples
32+
33+
See [examples/basic_parse.rs](examples/basic_parse.rs) for a complete example.
34+
35+
```bash
36+
cargo run --example basic_parse
37+
```
38+
39+
## Status
40+
41+
Basic parsing implemented. More FORTRAN constructs are being added.
42+
43+
## License
44+
45+
MIT
46+
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
use fortran_parser::parse;
2+
3+
fn main() -> Result<(), Box<dyn std::error::Error>> {
4+
let source = r#"
5+
program hello_world
6+
implicit none
7+
integer :: i
8+
real :: x
9+
10+
x = 3.14159
11+
do i = 1, 10
12+
if (i .gt. 5) then
13+
print *, 'Greater than 5: ', i
14+
else
15+
print *, 'Less than or equal to 5: ', i
16+
end if
17+
end do
18+
19+
print *, 'Hello, World!'
20+
end program hello_world
21+
"#;
22+
23+
println!("Parsing FORTRAN source...\n");
24+
25+
let program = parse(source)?;
26+
27+
println!("Successfully parsed program!");
28+
println!("Program unit: {:?}", program.program_unit);
29+
30+
Ok(())
31+
}
32+

fortran-parser/src/error.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
use fortran_lexer::LexError;
2+
use fortran_lexer::Token;
3+
4+
/// Parser error.
5+
#[derive(Debug, Clone, PartialEq)]
6+
pub enum ParseError {
7+
/// Unexpected token found.
8+
UnexpectedToken {
9+
expected: Vec<String>,
10+
found: Token,
11+
},
12+
/// Unexpected end of file.
13+
UnexpectedEof {
14+
expected: Vec<String>,
15+
},
16+
/// Lexer error.
17+
LexerError(LexError),
18+
/// Invalid syntax.
19+
InvalidSyntax {
20+
message: String,
21+
line: usize,
22+
column: usize,
23+
},
24+
}
25+
26+
pub type ParseResult<T> = Result<T, ParseError>;
27+
28+
impl std::fmt::Display for ParseError {
29+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30+
match self {
31+
ParseError::UnexpectedToken { expected, found } => {
32+
write!(
33+
f,
34+
"Unexpected token {:?} at line {}, column {}. Expected: {}",
35+
found.token_type,
36+
found.line,
37+
found.column,
38+
expected.join(" or ")
39+
)
40+
}
41+
ParseError::UnexpectedEof { expected } => {
42+
write!(
43+
f,
44+
"Unexpected end of file. Expected: {}",
45+
expected.join(" or ")
46+
)
47+
}
48+
ParseError::LexerError(err) => {
49+
write!(f, "Lexer error: {}", err)
50+
}
51+
ParseError::InvalidSyntax { message, line, column } => {
52+
write!(f, "Invalid syntax at line {}, column {}: {}", line, column, message)
53+
}
54+
}
55+
}
56+
}
57+
58+
impl std::error::Error for ParseError {
59+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
60+
match self {
61+
ParseError::LexerError(err) => Some(err),
62+
_ => None,
63+
}
64+
}
65+
}
66+
67+
impl From<LexError> for ParseError {
68+
fn from(err: LexError) -> Self {
69+
ParseError::LexerError(err)
70+
}
71+
}
72+

fortran-parser/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//! FORTRAN parser library.
2+
//!
3+
//! Provides a recursive descent parser for FORTRAN source code that converts
4+
//! tokens into an Abstract Syntax Tree (AST).
5+
6+
pub mod error;
7+
pub mod parser;
8+
9+
pub use error::{ParseError, ParseResult};
10+
pub use parser::{parse, Parser};

0 commit comments

Comments
 (0)