mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-27 10:18:36 +00:00
[flang] Markdown improvements.
Original-commit: flang-compiler/f18@f40b5e40df
This commit is contained in:
parent
1e69ed0c1b
commit
6e22a3563e
@ -10,49 +10,54 @@
|
||||
1. File names should use dashes, not underscores. C++ sources have the
|
||||
extension ".cc", not ".C" or ".cpp" or ".cxx". Don't create needless
|
||||
source directory hierarchies.
|
||||
1. Header files should be idempotent. Use the usual "#ifndef FORTRAN_header_H_",
|
||||
"#define FORTRAN_header_H_", and "#endif // FORTRAN_header_H_" technique.
|
||||
1. #include every header defining an entity that your project header or source
|
||||
1. Header files should be idempotent. Use the usual technique:
|
||||
```
|
||||
#ifndef FORTRAN_header_H_
|
||||
#define FORTRAN_header_H_
|
||||
// code
|
||||
#endif // FORTRAN_header_H_
|
||||
```
|
||||
1. `#include` every header defining an entity that your project header or source
|
||||
file actually uses directly. (Exception: when foo.cc starts, as it should,
|
||||
with #include "foo.h", and foo.h includes bar.h in order to define the
|
||||
interface to the module foo, you don't have to redundantly #include "bar.h"
|
||||
with `#include "foo.h"`, and foo.h includes bar.h in order to define the
|
||||
interface to the module foo, you don't have to redundantly `#include "bar.h"`
|
||||
in foo.cc.)
|
||||
1. In the source file "foo.cc", put the #include of "foo.h" first.
|
||||
Then #include other project headers in alphabetic order; then C++ standard
|
||||
1. In the source file "foo.cc", put the `#include "foo.h"` first.
|
||||
Then `#include` other project headers in alphabetic order; then C++ standard
|
||||
headers, also alphabetically; then C and system headers.
|
||||
1. Don't include the standard iostream header. If you need it for debugging,
|
||||
1. Don't use `#include <iostream>`. If you need it for debugging,
|
||||
remove the inclusion before committing.
|
||||
### Naming
|
||||
1. C++ names that correspond to STL names should look like those STL names
|
||||
(e.g., *clear()* and *size()* member functions in a class that implements
|
||||
(e.g., `clear()` and `size()` member functions in a class that implements
|
||||
a container).
|
||||
1. Non-public data members should be named with leading miniscule (lower-case)
|
||||
letters, internal camelCase capitalization, and a trailing underscore,
|
||||
e.g. "DoubleEntryBookkeepingSystem myLedger_;". POD structures with
|
||||
e.g. `DoubleEntryBookkeepingSystem myLedger_;`. POD structures with
|
||||
only public data members shouldn't use trailing underscores, since they
|
||||
don't have class functions in which data members need to be distinguishable.
|
||||
1. Accessor member functions are named with the non-public data member's name,
|
||||
less the trailing underscore. Mutator member functions are named *set_...*
|
||||
and should return "*this". Don't define accessors or mutators needlessly.
|
||||
less the trailing underscore. Mutator member functions are named `set_...`
|
||||
and should return `*this`. Don't define accessors or mutators needlessly.
|
||||
1. Other class functions should be named with leading capital letters,
|
||||
CamelCase, and no underscores, and, like all functions, should be based
|
||||
on imperative verbs, e.g. *HaltAndCatchFire()*.
|
||||
on imperative verbs, e.g. `HaltAndCatchFire()`.
|
||||
1. It is fine to use short names for local variables with limited scopes,
|
||||
especially when you can declare them directly in a for()/while()/if()
|
||||
especially when you can declare them directly in a `for()`/`while()`/`if()`
|
||||
condition. Otherwise, prefer complete English words to abbreviations
|
||||
when creating names.
|
||||
### Commentary
|
||||
1. Use // for all comments except for short notes within expressions.
|
||||
1. When // follows code on a line, precede it with two spaces.
|
||||
1. Use `//` for all comments except for short `/*notes*/` within expressions.
|
||||
1. When `//` follows code on a line, precede it with two spaces.
|
||||
1. Comments should matter. Assume that the reader knows current C++ at least as
|
||||
well as you do and avoid distracting her by calling out usage of new
|
||||
features in comments.
|
||||
### Layout
|
||||
Always run *clang-format* before committing code. Other developers should
|
||||
be able to run "git pull", then *clang-format*, and see only their own
|
||||
Always run `clang-format` before committing code. Other developers should
|
||||
be able to run `git pull`, then `clang-format`, and see only their own
|
||||
changes.
|
||||
|
||||
Here's what you can expect to see *clang-format* do:
|
||||
Here's what you can expect to see `clang-format` do:
|
||||
1. Indent with two spaces.
|
||||
1. Don't indent public:, protected:, and private:
|
||||
accessibility labels.
|
||||
@ -65,12 +70,12 @@ names.
|
||||
Don't try to make columns of variable names or comments
|
||||
align vertically -- they are maintenance problems.
|
||||
|
||||
Always wrap the bodies of if(), else, while(), for(), do, &c.
|
||||
Always wrap the bodies of `if()`, `else`, `while()`, `for()`, `do`, &c.
|
||||
with braces, even when the body is a single statement or empty. The
|
||||
opening { goes on
|
||||
opening `{` goes on
|
||||
the end of the line, not on the next line. Functions also put the opening
|
||||
{ after the formal arguments or new-style result type, not on the next
|
||||
line. Use {} for empty inline constructors and destructors in classes.
|
||||
`{` after the formal arguments or new-style result type, not on the next
|
||||
line. Use `{}` for empty inline constructors and destructors in classes.
|
||||
|
||||
Don't waste space on the screen with needless blank lines or elaborate block
|
||||
commentary (lines of dashes, boxes of asterisks, &c.). Write code so as to be
|
||||
@ -79,39 +84,40 @@ easily read and understood with a minimum of scrolling.
|
||||
Use *C++17*, unless some compiler to which we must be portable lacks a feature
|
||||
you are considering.
|
||||
1. Never throw or catch exceptions.
|
||||
1. Never use run-time type information or dynamic_cast<>.
|
||||
1. Never use run-time type information or `dynamic_cast<>`.
|
||||
1. Never declare static data that executes a constructor.
|
||||
Use {braced initializers} in all circumstances where they work, including
|
||||
(This is why `#include <iostream>` is contraindicated.)
|
||||
Use `{braced initializers}` in all circumstances where they work, including
|
||||
default data member initialization. They inhibit implicit truncation.
|
||||
Don't use "= expr" initialization just to effect implicit truncation;
|
||||
prefer an explicit static_cast<>.
|
||||
1. Avoid unsigned types apart from size_t, which must be used with care.
|
||||
When *int* just obviously works, just use *int*. When you need something
|
||||
bigger than *int*, use std::int64_t rather than *long* or long long.
|
||||
Don't use `= expr` initialization just to effect implicit truncation;
|
||||
prefer an explicit `static_cast<>`.
|
||||
1. Avoid unsigned types apart from `size_t`, which must be used with care.
|
||||
When `int` just obviously works, just use `int`. When you need something
|
||||
bigger than `int`, use `std::int64_t` rather than `long` or `long long`.
|
||||
1. Use namespaces to avoid conflicts with client code. Use one top-level
|
||||
project namespace. Don't introduce needless nested namespaces within a
|
||||
project when names don't conflict or better solutions exist. Never use
|
||||
"using namespace ...;", especially not "using namespace std;". Access
|
||||
STL entities with names like std::unique_ptr<>, without a leading "::".
|
||||
`using namespace ...;`, especially not `using namespace std;`. Access
|
||||
STL entities with names like `std::unique_ptr<>`, without a leading `::`.
|
||||
1. Prefer static functions to functions in anonymous namespaces in source files.
|
||||
1. Use *auto* judiciously. When the type of a local variable is known,
|
||||
monomorphic, and easy to type, be explicit rather than using *auto*.
|
||||
1. Use `auto` judiciously. When the type of a local variable is known,
|
||||
monomorphic, and easy to type, be explicit rather than using `auto`.
|
||||
1. Use move semantics and smart pointers to make dynamic memory ownership
|
||||
clear. Consider reworking any code that uses malloc() or a (non-placement)
|
||||
operator new.
|
||||
1. Use references for const arguments; prefer const references to values for
|
||||
all but small types that are trivially copyable (e.g., *int*). Use non-const
|
||||
pointers for output arguments. Put output arguments last (pace the standard
|
||||
C library conventions for memcpy() & al.).
|
||||
1. Prefer *typename* to *class* in template argument declarations.
|
||||
1. Prefer enum class to plain enum wherever enum class will work.
|
||||
1. Use constexpr and const generously.
|
||||
1. When a switch() statement's labels do not cover all possible case values
|
||||
explicitly, it should contains either a "default:;" at its end or a
|
||||
default: label that obviously crashes.
|
||||
clear. Consider reworking any code that uses `malloc()` or a (non-placement)
|
||||
`operator new`.
|
||||
1. Use references for `const` arguments; prefer `const` references to values for
|
||||
all but small types that are trivially copyable (e.g., use `const std::string &`
|
||||
and `int`). Use non-`const` pointers for output arguments. Put output arguments
|
||||
last (_pace_ the standard C library conventions for `memcpy()` & al.).
|
||||
1. Prefer `typename` to `class` in template argument declarations.
|
||||
1. Prefer `enum class` to plain `enum` wherever `enum class` will work.
|
||||
1. Use `constexpr` and `const` generously.
|
||||
1. When a `switch()` statement's labels do not cover all possible case values
|
||||
explicitly, it should contains either a `default:;` at its end or a
|
||||
`default:` label that obviously crashes.
|
||||
#### Classes
|
||||
1. Define only POD structures with struct.
|
||||
1. Don't use "this->" in (non-static) member functions.
|
||||
1. Define only POD structures with `struct`.
|
||||
1. Don't use `this->` in (non-static) member functions.
|
||||
1. Define accessor and mutator member functions (implicitly) inline in the
|
||||
class, after constructors and assignments. Don't needlessly define
|
||||
(implicit) inline member functions in classes unless they really solve a
|
||||
@ -121,7 +127,7 @@ interfaces, at least to the extent that C++ allows.
|
||||
1. When copy constructors and copy assignment are not necessary,
|
||||
and move constructors/assignment is present, don't declare them and they
|
||||
will be implicitly deleted. When neither copy nor move constructors
|
||||
or assignments should exist for a class, explicitly delete all of them.
|
||||
or assignments should exist for a class, explicitly `=delete` all of them.
|
||||
1. Make single-argument constructors (other than copy and move constructors)
|
||||
explicit unless you really want to define an implicit conversion.
|
||||
#### Overall design preferences
|
||||
|
@ -4,31 +4,31 @@ descent parser. It is composed from a *parser combinator* library that
|
||||
defines a few fundamental parsers and a few ways to compose them into more
|
||||
powerful parsers.
|
||||
|
||||
For our purposes here, a *parser* is any object that can attempt to recognize
|
||||
For our purposes here, a *parser* is any object that attempts to recognize
|
||||
an instance of some syntax from an input stream. It may succeed or fail.
|
||||
On success, it may return some semantic value to its caller.
|
||||
|
||||
In C++ terms, a parser is any instance of a class that
|
||||
1. has a *constexpr* default constructor,
|
||||
1. defines a resultType type, and
|
||||
1. provides a member or static function that accepts a pointer to a
|
||||
ParseState as its argument and returns a std::optional<resultType> as a
|
||||
result, with the presence or absence of a value in the std::optional<>
|
||||
1. has a `constexpr` default constructor,
|
||||
1. defines a type named `resultType`, and
|
||||
1. provides a function (`const` member or static) that accepts a pointer to a
|
||||
ParseState as its argument and returns a `std::optional<resultType>` as a
|
||||
result, with the presence or absence of a value in the `std::optional<>`
|
||||
signifying success or failure, respectively.
|
||||
|
||||
> std::optional<resultType> Parse(ParseState *) const;
|
||||
|
||||
The resultType of a parser is typically the class type of some particular
|
||||
```
|
||||
std::optional<resultType> Parse(ParseState *) const;
|
||||
```
|
||||
The `resultType` of a parser is typically the class type of some particular
|
||||
node type in the parse tree.
|
||||
|
||||
*ParseState* is a class that encapsulates a position in the source stream,
|
||||
collects messages, and holds a few state flags that determive tokenization
|
||||
(e.g., are we in a character literal?). Instances of *ParseState* are
|
||||
`ParseState` is a class that encapsulates a position in the source stream,
|
||||
collects messages, and holds a few state flags that determine tokenization
|
||||
(e.g., are we in a character literal?). Instances of `ParseState` are
|
||||
independent and complete -- they are cheap to duplicate whenever necessary to
|
||||
implement backtracking.
|
||||
|
||||
The constexpr default constructor of a parser is important. The functions
|
||||
(below) that operate on instances of parsers are themselves all constexpr.
|
||||
The `constexpr` default constructor of a parser is important. The functions
|
||||
(below) that operate on instances of parsers are themselves all `constexpr`.
|
||||
This use of compile-time expressions allows the entirety of a recursive
|
||||
descent parser for a language to be constructed at compilation time through
|
||||
the use of templates.
|
||||
@ -36,110 +36,115 @@ the use of templates.
|
||||
### Fundamental Predefined Parsers
|
||||
These objects and functions are (or return) the fundamental parsers:
|
||||
|
||||
* *ok* is a trivial parser that always succeeds without advancing.
|
||||
* "pure(x)" returns a trivial parser that always succeeds without advancing,
|
||||
returning some value *x*.
|
||||
* "fail<T>(msg)" denotes a trivial parser that always fails, emitting the
|
||||
given message. The template parameter is the type of the value that
|
||||
the parser never returns.
|
||||
* *cut* is a trivial parser that always fails silently.
|
||||
* "guard(pred)" returns a parser that succeeds if and only if the predicate
|
||||
* `ok` is a trivial parser that always succeeds without advancing.
|
||||
* `pure(x)` returns a trivial parser that always succeeds without advancing,
|
||||
returning some value `x`.
|
||||
* `fail<T>(msg)` denotes a trivial parser that always fails, emitting the
|
||||
given message as a side effect. The template parameter is the type of
|
||||
the value that the parser never returns.
|
||||
* `cut` is a trivial parser that always fails silently.
|
||||
* `guard(pred)` returns a parser that succeeds if and only if the predicate
|
||||
expression evaluates to true.
|
||||
* *rawNextChar* returns the next raw character, and fails at EOF.
|
||||
* *cookedNextChar* returns the next character after preprocessing, skipping
|
||||
* `rawNextChar` returns the next raw character, and fails at EOF.
|
||||
* `cookedNextChar` returns the next character after preprocessing, skipping
|
||||
Fortran line continuations and comments; it also fails at EOF
|
||||
|
||||
### Combinators
|
||||
These functions and operators combine parsers to generate new parsers.
|
||||
These functions and operators combine existing parsers to generate new parsers.
|
||||
They are `constexpr`, so they should be viewed as type-safe macros.
|
||||
|
||||
* "!p" succeeds if p fails, and fails if p succeeds.
|
||||
* "p >> q" fails if p does, otherwise running q and returning its value when
|
||||
* `!p` succeeds if p fails, and fails if p succeeds.
|
||||
* `p >> q` fails if p does, otherwise running q and returning its value when
|
||||
it succeeds.
|
||||
* "p / q" fails if p does, otherwise running q and returning *p's* value
|
||||
* `p / q` fails if p does, otherwise running q and returning p's value
|
||||
if q succeeds.
|
||||
* "p || q" succeeds if p does, otherwise running q. The two parsers must
|
||||
* `p || q` succeeds if p does, otherwise running q. The two parsers must
|
||||
have the same type, and the value returned by the first succeeding parser
|
||||
is the value of the combination.
|
||||
* "lookAhead(p)" succeeds if p does, but doesn't modify any state.
|
||||
* "attempt(p)" succeeds if p does, safely preserving state on failure.
|
||||
* "many(p)" recognizes a greedy sequence of zero or more nonempty successes
|
||||
of *p*, and returns std::list<> of their values. It always succeeds.
|
||||
* "some(p)" recognized a greedy sequence of one or more successes of *p*.
|
||||
* `lookAhead(p)` succeeds if p does, but doesn't modify any state.
|
||||
* `attempt(p)` succeeds if p does, safely preserving state on failure.
|
||||
* `many(p)` recognizes a greedy sequence of zero or more nonempty successes
|
||||
of p, and returns `std::list<>` of their values. It always succeeds.
|
||||
* `some(p)` recognized a greedy sequence of one or more successes of p.
|
||||
It fails if p immediately fails.
|
||||
* "skipMany(p)" is the same as "many(p)", but it discards the results.
|
||||
* "maybe(p)" tries to match *p*, returning an "std::optional<T>" value.
|
||||
* `skipMany(p)` is the same as `many(p)`, but it discards the results.
|
||||
* `maybe(p)` tries to match p, returning an `std::optional<T>` value.
|
||||
It always succeeds.
|
||||
* "defaulted(p)" matches *p*, and when *p* fails it returns a
|
||||
default-constructed instance of *p*'s resultType. It always succeeds.
|
||||
* "nonemptySeparated(p, q)" repeatedly matches "p q p q p q ... p",
|
||||
returning a std::list<> of only the values of the p's. It fails if
|
||||
*p* immediately fails.
|
||||
* "extension(p)" parses *p* if strict standard compliance is disabled,
|
||||
* `defaulted(p)` matches p, and when p fails it returns a
|
||||
default-constructed instance of p's resultType. It always succeeds.
|
||||
* `nonemptySeparated(p, q)` repeatedly matches "p q p q p q ... p",
|
||||
returning a `std::list<>` of only the values of the p's. It fails if
|
||||
p immediately fails.
|
||||
* `extension(p)` parses p if strict standard compliance is disabled,
|
||||
or with a warning if nonstandard usage warnings are enabled.
|
||||
* "deprecated(p)" parses *p* if strict standard compliance is disabled,
|
||||
* `deprecated(p)` parses p if strict standard compliance is disabled,
|
||||
with a warning if deprecated usage warnings are enabled.
|
||||
* "inContext(..., p)" runs *p* within an error message context.
|
||||
* `inContext(..., p)` runs p within an error message context.
|
||||
|
||||
Note that "a >> b >> c / d / e" matches a sequence of five parsers,
|
||||
but returns only the result that was obtained by matching c.
|
||||
Note that
|
||||
```
|
||||
a >> b >> c / d / e
|
||||
```
|
||||
matches a sequence of five parsers, but returns only the result that was
|
||||
obtained by matching `c`.
|
||||
|
||||
### Applicatives
|
||||
The following *applicative* combinators combine parsers and modify or
|
||||
collect the values that they return.
|
||||
|
||||
* "construct<T>{}(p1, p2, ...)" matches zero or more parsers in succession,
|
||||
* `construct<T>{}(p1, p2, ...)` matches zero or more parsers in succession,
|
||||
collecting their results and then passing them with move semantics to a
|
||||
constructor for the type *T* if they all succeed.
|
||||
* "applyFunction(f, p1, p2, ...)" matches one or more parsers in succession,
|
||||
constructor for the type T if they all succeed.
|
||||
* `applyFunction(f, p1, p2, ...)` matches one or more parsers in succession,
|
||||
collecting their results and passing them as rvalue reference arguments to
|
||||
some function, returning its result.
|
||||
* "applyLambda([](&&x){}, p1, p2, ...)" is the same thing, but for lambdas
|
||||
* `applyLambda([](&&x){}, p1, p2, ...)` is the same thing, but for lambdas
|
||||
and other function objects.
|
||||
* "applyMem(mf, p1, p2, ...)" is the same thing, but invokes a member
|
||||
* `applyMem(mf, p1, p2, ...)` is the same thing, but invokes a member
|
||||
function of the result of the first parser for updates in place.
|
||||
|
||||
### Non-Advancing State Inquiries and Updates
|
||||
These are non-advancing state inquiry and update parsers:
|
||||
|
||||
* *getColumn* returns the 1-based column position.
|
||||
* *inCharLiteral* succeeds under withinCharLiteral.
|
||||
* *inFortran* succeeds unless in a preprocessing directive.
|
||||
* *inFixedForm* succeeds in fixed-form source.
|
||||
* *setInFixedForm* sets the fixed-form flag, returning its prior value.
|
||||
* *columns* returns the 1-based column number after which source is clipped.
|
||||
* "setColumns(c)" sets the column limit and returns its prior value.
|
||||
* `getColumn` returns the 1-based column position.
|
||||
* `inCharLiteral` succeeds under withinCharLiteral.
|
||||
* `inFortran` succeeds unless in a preprocessing directive.
|
||||
* `inFixedForm` succeeds in fixed-form source.
|
||||
* `setInFixedForm` sets the fixed-form flag, returning its prior value.
|
||||
* `columns` returns the 1-based column number after which source is clipped.
|
||||
* `setColumns(c)` sets the column limit and returns its prior value.
|
||||
|
||||
### Monadic Combination
|
||||
When parsing depends on the result values of earlier parses, the
|
||||
"monadic bind" combinator is available.
|
||||
*monadic bind* combinator is available.
|
||||
Please try to avoid using it, as it makes automatic analysis of the
|
||||
grammar difficult.
|
||||
It has the syntax "p >>= f", and it constructs a parser that matches p,
|
||||
It has the syntax `p >>= f`, and it constructs a parser that matches p,
|
||||
yielding some value x on success, then matches the parser returned from
|
||||
the function call "f(x)".
|
||||
the function call `f(x)`.
|
||||
|
||||
### Token Parsers
|
||||
Last, we have these basic parsers on which the actual grammar of the Fortran
|
||||
is built. All of the following parsers consume characters acquired from
|
||||
*cookedNextChar*.
|
||||
`cookedNextChar`.
|
||||
|
||||
* *spaces* always succeeds after consuming any spaces or tabs
|
||||
* *digit* matches one cooked decimal digit (0-9)
|
||||
* *letter* matches one cooked letter (A-Z)
|
||||
* "CharMatch<'c'>{}" matches one specific cooked character.
|
||||
* "..."_tok match the content of the string, skipping spaces before and
|
||||
* `spaces` always succeeds after consuming any spaces or tabs
|
||||
* `digit` matches one cooked decimal digit (0-9)
|
||||
* `letter` matches one cooked letter (A-Z)
|
||||
* `CharMatch<'c'>{}` matches one specific cooked character.
|
||||
* `"..."_tok` match the content of the string, skipping spaces before and
|
||||
after, and with multiple spaces accepted for any internal space.
|
||||
(Note that the _tok suffix is optional when the parser appears before
|
||||
the combinator ">>" or after "/".)
|
||||
* "parenthesized(p)" is shorthand for "(" >> p / ")".
|
||||
* "bracketed(p)" is shorthand for "[" >> p / "]".
|
||||
* "withinCharLiteral(p)" applies the parser *p*, tokenizing for
|
||||
(Note that the `_tok` suffix is optional when the parser appears before
|
||||
the combinator`">>` or after `/`.)
|
||||
* `parenthesized(p)` is shorthand for `"(" >> p / ")"`.
|
||||
* `bracketed(p)` is shorthand for `"[" >> p / "]"`.
|
||||
* `withinCharLiteral(p)` applies the parser p, tokenizing for
|
||||
CHARACTER/Hollerith literals.
|
||||
* "nonEmptyListOf(p)" matches a comma-separated list of one or more
|
||||
instances of *p*.
|
||||
* "optionalListOf(p)" is the same thing, but can be empty, and always succeeds.
|
||||
* `nonEmptyListOf(p)` matches a comma-separated list of one or more
|
||||
instances of p.
|
||||
* `optionalListOf(p)` is the same thing, but can be empty, and always succeeds.
|
||||
|
||||
### Debugging Parser
|
||||
Last, the parser "..."_debug emit the string to the standard error and succeeds.
|
||||
It is useful for tracing while debugging a parser but should obviously not
|
||||
be committed for production code.
|
||||
Last, the parser `"..."_debug` emits the string to the standard error
|
||||
and succeeds. It is useful for tracing while debugging a parser but should
|
||||
obviously not be committed for production code.
|
||||
|
Loading…
Reference in New Issue
Block a user