Pecan is a tool for developing and checking grammars, and generating scanners and parsers. It is aimed at parsers for programming languages, domain specific languages, and other unambiguous computer languages. It provides a precise grammar notation, which is independent of implementation language, based on recursive descent with lookahead. This manual describes Pecan version 1.0 which has these features:
Having a separate notation for grammars helps to focus attention on the various issues that have to be addressed, separately from the programming details. However, that also makes grammars rather dense. Creating or translating a grammar accurately can be difficult. In addition, programmers typically use parser generators only rarely, and are often not grammar experts. For those reasons, Pecan has explicit support for test-driven grammar development.
The Pecan system is written in Java, so the first step is to make sure that
version 8 or better of Java is available. Pecan is provided as an executable jar
file pecan.jar
. If this jar file is downloaded, it can be run
with:
java -jar pecan.jar ...
However, it is more convenient to create a batch file or shell script, or use an alias or equivalent, so that the program can be run just by typing:
pecan ...
The way to do this differs from system to system, so isn't described here. To run tests on a grammar, type a command of the form:
pecan [-t | -trace] [line] testfile
To compile a grammar, type a command of the form:
pecan grammar -c programfile
The option -c programfile
indicates that the grammar is to be
compiled to a set of recursive descent functions. The program is a template in
the desired target programming language, into which the functions are embedded,
to form a parser or application program. To translate a grammar to bytecode,
type a command:
pecan grammar -b binaryfile
The option -b binaryfile
indicates that the grammar is to be
compiled into a bytecode array in the given binary file. This can then be loaded
into an interpreter program in any desired language to form a parser or
application program.
Other approaches to developing parsers are usually based on writing them manually in the recursive descent style, or using a parser generator based on the context free grammar (CFG) formalism, or the parsing expression grammar (PEG) notation.
Recursive descent parsers have the advantage of being efficient, intuitive, and capable of being hand-written. However, for large projects, parsers tend to become repetitive and error prone. One of the main problems is that a simple approach is hardly ever enough. In order to deal with the difficult cases which arise in practice, extra features such as lookahead or backtracking are needed. These extra features are often added in an ad hoc fashion on practical grounds, which typically makes parsers complex, obscure and error-prone.
A library of parser combinators can ease the process of writing a parser in the recursive descent style, by providing components which reduce verbosity and automate features such as lookahead. However, a combinator library typically still has two problems. The first is that parsers have to be written in a specific language in which the library is written, or to which the library has been ported. The second is that there is typically no separate and independent grammar, and so there is a shortage of analysis and development tools to help with the development of parsers.
The CFG notation (in the form of BNF and many variations) has been the main formalism for grammars for a long time, and it has been well studied. However, it has been argued quite strongly that it is not an ideal formalism to use for unambiguous languages. According to Bryan Ford:
The power of generative grammars to express ambiguity is crucial to their original purpose of modelling natural languages, but this very power makes it unnecessarily difficult both to express and to parse machine-oriented languages using CFGs.
One fundamental theoretical problem is that CFG grammars can contain ambiguities, and there is no computable algorithm to detect whether or not a grammar is unambiguous. There is also the associated practical problem that many published CFG grammars contain ambiguities. Some of these are local, i.e. a particular rule allows two possible parses, but there is a surrounding, more global, rule that resolves the ambiguity by only accepting one of the possibilities. But many ambiguities in published grammars are inherent, the ambiguity being resolved only by accompanying descriptive text or particular approaches to generating parsers.
As well as ambiguity, there is also the problem that a CFG grammar describes a language in a generative way, which is not directly and intuitively linked to the recognition problem faced in parsing. Indeed the meaning of a grammar is often different from the parser generated from it. There is an awkward semantic gap.
Conventional CFG-based parser generators have a variety of other flaws, partly due to the difficulties of the CFG formalism, and partly due to the age of their designs. They often have arbitrary heuristic rules for disambiguation. They often support a subset of CFG grammars which is not at all intuitive. They often use bottom-up parsing techniques to make parsers near-linear, which makes the way they operate impenetrable. And they often support actions and error reporting using embedded code fragments which are not part of the grammar. The code fragments are often restricted to a particular implementation language, and the approach is any case very fragile.
These problems with the CFG formalism might be worth putting up with, if the formalism had excellent theoretical or practical properties. But it doesn't. For example, CFG grammars have poor composability properties, and poor closure properties. And, in general, parsing CFG grammars takes O(n3) time in the worst case.
The main difference with PEG grammars compared to CFG grammars is that the
symmetrical choice operator |
is replaced by an ordered choice
operator /
which has a more operational meaning. The expressive
power of PEG grammars is extremely close to that of CFG grammars. Certainly,
grammars for all practical everyday languages can be expressed in either
notation.
The theoretical and practical properties of the PEG formalism are far superior to the CFG formalism. PEG grammars never contain any ambiguity, they have a direct operational meaning as parsers, they are composable, they are closed under many operations, and they can be parsed in linear time using the packrat algorithm. This makes the PEG grammar formalism a much better starting point for studying grammars and parsers.
Unfortunately, there are practical problems with PEG parsers. Although the packrat algorithm is linear, it is slower and more space hungry than one would like for efficient large scale parsing. Also, because of the implicit unlimited backtracking, it can be difficult to understand or predict the operation of PEGs, it is difficult to produce accurate error messages, and difficult to express actions. As a result, PEG grammars are typically only used for search expressions, or for small domain specific languages, and not for larger applications such as full programming languages.
There is also a relatively minor problem with PEG grammars, which is that they don't support left recursion. There have been attempts to add it, but the results are not compelling. Most uses of left recursion are very simple, of the kind:
a = x | a y
This can be translated very easily into:
a = x y*
It is well known how to transform away any cases of left recursion. It is worth noting that left recursion is arguably unintuitive, and that it would probably never have become common if it weren't for the prevalence of CFG grammars.
Pecan provides a notation for grammars which is an adaptation of the PEG notation to remove the implicit backtracking. Actions and markers for error handling are easily embedded as symbols, independently of any target programming language. Explicit lookahead features are provided to help in making choices, but they don't involve actions or error handling, so a grammar closely corresponds to conventional simple recursive descent.
Pecan provides direct support for parser development. Tools are provided to aid in development and testing, including consistency checks on grammars, features for automated testing, and the ability to execute grammars as symbolic parsers.
Manual transformations can be carried out on grammars, e.g. to convert CFG grammars into Pecan grammars or improve efficiency, and these preserve the actions and error handling properties of generated parsers.
Once a grammar has been developed, it can be compiled into a set of recursive descent functions in almost any desired target programming language. A grammar can alternatively be translated into a bytecode, so that it can be dynamically loaded into an application.
The Pecan language is a grammar language for writing parsers, loosely based
on the PEG
notation. Pecan has a sequential choice operator x/y
but, unlike
the PEG notation, the operator does not automatically involve backtracking.
There are separate lookahead operators, for the controlled use of backtracking,
which provide greater control over the progress of parsing. That makes it much
easier to generate accurate error messages, while having the full power of the
PEG notation available to decide between alternatives. The approach gives
programmers the expressiveness to make parsers efficient without relying on
obscure automatic optimisations, and parsers normally run without the space
overhead of such techniques as the PEG packrat algorithm. The syntax of Pecan
grammars is explained below. For reference, there is a Pecan grammar for the
Pecan language, with tests, in the files:
As with PEG grammars, any parsing expression within a grammar represents a matching operation which succeeds or fails when applied at a particular position in the input, and which may cause progress, i.e. may cause the current position to move forwards in the input, according to how much of it is matched.
A parser consists of a sequence of rules, each of which gives a name to a parsing expression. By default, the first rule specifies the output of the whole parsing process. For example, a parser might start with:
module = function+ <> function = id arguments body ...
Apart from being the starting point of the parser, the first rule is not
treated in any special way. In particular, it may succeed without consuming all
the input. So an explicit test is often included, as here, to check that the end
of the input has been reached. The notation <>
which is a less
than sign followed by a greater than sign, matches the end of the input.
An identifier introduced by a rule starts with a letter and continues with letters, digits, hyphens or underscores. The text of a grammar is assumed to be encoded using UTF-8, so Unicode letter and digit characters can be included. There is also a literal form of identifier, consisting of arbitrary characters in backquotes, which is described further in the section on literal names below.
In place of a rule, an inclusion may be used:
{expressions.txt}
This is a string giving a file name or path to another file of grammar rules to be included at this point. This can help in presenting and testing large grammars in a modular way.
If a parser fails, only the first failure is reported. There is no attempt to recover. If error recovery is required, this can be accomplished by writing a separate rule to be tried on the remaining input.
Comments start with --
and extend to the end of the line. For
example:
-- A number is a sequence of one or more digits. number = '0..9'+
There is no multi-line comment convention.
Parentheses, i.e. round brackets, have their usual meaning, indicating grouping of operations. For example:
(x / y) z
means parse x
or y
, then parse z
, as
opposed to:
x / y z
which means either parse x
, or else parse y
and
z
.
No explicit symbol is used to terminate a rule. A rule is terminated at the
end of a line, unless it is continued. A rule is continued on the next line if
the last token on the current line is an infix symbol or open bracket, i.e. one
of =/([
. Here is an example rule where each line except the last
ends with =
or the /
operator:
atom = id / number / bracket
Also, a rule is continued on the next line if the first token of the next
line is an infix symbol or close bracket, i.e. one of =/)]
. This
allows an alternative style for a multi-line rule:
atom = id / number / bracket
In this example, each line that starts with =
or /
is a continuation of the previous line.
The choice operator /
separates alternatives, which are tried
one after the other. For example:
atom = id / number / bracket
If parsing of an alternative succeeds, then the parsing of the whole expression succeeds. Otherwise, if no progress was made, the next alternative is tried.
The choice operator involves a single item lookahead. If progress is made on an alternative, i.e. at least one input character or token is matched, then the parser is committed to that alternative, and further alternatives are not tried.
There are separate lookahead operators which allow speculative parsing of an alternative with backtracking.
When items follow each other with no visible operator in between, this indicates "followed by". For example:
assignment = identifier "=" expression
This means that an assignment is an identifier followed by an equals sign followed by an expression. The items are parsed one by one and, if parsing of any item fails, parsing of the sequence is abandoned. Sequencing binds tighter than the choice operator.
There are three postfix repetition operators. The *
operator
indicates that an item is to be repeated any number of times, i.e. zero or more
times. The +
operator indicates that an item is to be repeated one
or more times. The ?
operator indicates that an item is optional,
i.e. repeated zero times or once. Postfix operators bind tighter than
sequencing, so x y*
means x (y*)
. Examples are:
string = '"' stringchar* '"' number = digit+ call = function "(" arguments? ")"
The string
rule specifies that a string consists of a double
quote followed by any number of allowable characters followed by a closing
double quote. The number
rule specifies that a number consists of
one or more digits. The call
rule specifies that a call consists of
a function name followed by brackets, and the brackets may optionally contain
arguments.
The three expressions x*
, x+
, x?
act
in exactly the same way as the three rules xs
, xp
,
xq
defined by:
xs = x xs / "" xp = x (xp / "") xq = x / ""
This means that x*
or x+
will accept as
many x
's as are present in the input. In all three cases, in line
with the fact that the choice operator does no backtracking by default, if
progress is made on a final x
without success, the whole
expression fails.
There are three lookahead constructs, the see operator
[...]
, the has operator &
and the
not operator !
.
The see operator (also called the try or commit operator) is specified using
square brackets. In an expression [x]
, the subexpression
x
is parsed speculatively. If it succeeds, parsing continues as
normal. If it fails, the parser backtracks to the point just before
x
. The see operator is usually used to indicate the point at
which the parser should accept an alternative. For example:
statement = [identifier "="] expression / ...
This specifies that if the parser sees an identifier and equal sign, then it should commit to the first alternative. If an error occurs before that, e.g. an identifier has been matched but there is no equal sign, backtracking is done by resetting the parser to the point before the identifier, and the next alternative is tried.
The has &
and not !
operators represent
positive and negative lookahead. In the PEG notation, &
and
!
are prefix operators, but in Pecan, they are postfix, to make the
syntax of rules simpler and more uniform and, in particular, to avoid precedence
issues which would arise if there were both prefix and postfix operators. The
&
and !
operators bind more tightly than
sequencing.
With x&
or x!
, the expression x
is
parsed speculatively to check whether it appears next in the input or not.
Whether the expression x
succeeds or fails, the parser backtracks
to the beginning. Then x&
succeeds if the parsing of
x
succeeded, whereas x!
succeeds if the parsing of
x
failed. For example:
statement = (type identifier)& declaration / assignment
The parser looks ahead to see if there is a type and identifier next in the input. If there is, the parser backtracks to the point before the type, but continues with the same alternative and parses a declaration. If the lookahead fails, an assignment is parsed. A negative example is:
string = '"' ('"'! visible)* '"'
This says that a string contains any visible character other than a double quote. The bracketed expression only matches a visible character if a double quote does not appear next in the input.
Lookahead expressions are regarded only as ways to decide which alternative
to take, so actions and error reporting are suspended. During has and not
operations x&
or x!
, actions and error markers are
ignored. A see operation [x]
is equivalent to x&
x
, so actions and error reporting are only performed if x
succeeds.
Text notations are used to match input characters. Single quotes indicate
individual characters, e.g. 'x'
matches the letter x
.
Several characters in single quotes indicate a set of distinct alternatives, any
one of which can be matched. For example:
op = '+-*/' digit = '0123456789'
The expression '+-*/'
matches any one of the four arithmetic
operator characters, and is equivalent to '+' / '-' / '*' / '/'
.
The expression '0123456789'
matches any digit.
Double quotes indicate a string of characters, which are matched in sequence. For example:
keyword = "int" / "if" / "while" / ... pi = "π"
The string "int"
only matches if all three characters appear in
the input in sequence, i.e. it is equivalent to ['i' 'n' 't']
. The
square brackets indicate that if a string matches only partially, the input
position returns to the beginning of the string, and other alternatives can be
tried.
Single characters can be represented using either single or double quotes. For example:
double_quote = '"' single_quote = "'"
Grammar files are assumed to use the UTF-8 encoding, and any Unicode
characters can be used in set or string quotes. However, Pecan does not handle
normalization or graphemes, so care needs to be taken. For example,
'é'
is visually ambiguous because it could contain one or two code
points, depending on whether a combiner is used to add the accent. In Pecan
sets, each code point is treated as a separate character, so if é
consists of two code points, then 'é'
represents a choice between
those two code points. If the intended meaning is a single character, it is
better to write "é"
in case there are two code points. Similarly,
if the intention of 'éè'
is a choice between two characters, it is
better to write "é" / "è"
to avoid problems.
A range of characters can be expressed using two dots:
letter = 'a..z'
There must be one character (code point) either side of the two dots.
Common sets of characters can be specified using Unicode general categories.
The standard two-letter abbreviations for the Unicode general categories
Cc, Cf, Cn, Co, Cs, Ll, Lm, Lo, Lt, Lu, Mc, Me, Mn, Nd, Nl, No, Pc, Pd,
Pe, Pf, Pi, Po, Ps, Sc, Sk, Sm, So, Zl, Zp, Zs
are provided. In addition,
a dot .
stands for any Unicode code point. For example:
letter = Lu / Ll / Lt / Lm / Lo digit = Nd connector = '_'! Pc visible = (Cc/Cn/Co/Cs/Zl/Zp)! .
The Unicode categories starting with L
are letters. The letter
rule allows any kind of letters: upper case, lower case, title case, modifier
and other. Categories starting with N
are number characters, of
which Nd
is the set of decimal digits. The connector rule uses the
Pc
connector punctuation category, but excludes the underscore
character. The visible
rule matches any character, excluding code
points which are unassigned, private, surrogate, controls, or line or paragraph
separators.
A splitter is a string in angle brackets such as <abc>
which
represents a lookahead. It does not consume any input characters, but succeeds
if the remaining input, regarded as a string, is lexicographically less than or
equal to "abc"
. For example:
keyword = <df> keyword1 / keyword2 keyword1 = "break" / "case" / "catch" / "continue" / "default" keyword2 = "do" / "else" / "for" / "if" / "switch" / "while"
Here, some keywords are listed in alphabetical order, and a splitter is used
to speed up their recognition by separating the keywords up to
"default"
from the keywords from "do"
onwards. Note
that <default>
should not be used as the splitter in this
example, because if "default"
is next in the input, the input
continues after that and is therefore lexicographically greater. Nor should the
splitter be <do>
, just in case do
is at the end of
the input text.
The empty string ""
always succeeds, the empty set
''
always fails, and the empty splitter succeeds only at the end of
the input:
succeed = "" fail = '' end = <>
These can be particularly useful during transformations.
There are escape conventions within sets, strings, ranges, splitters and literal names (see later), to include control characters, or awkward characters, or to represent Unicode characters using plain text. A summary of the escape conventions is:
| Escape | Code | Character |
|---|---|---|
\r | 13 | return |
\n | 10 | newline |
\q | 39 | single quote |
\d | 34 | double quote |
\g | 96 | grave/backquote |
\b | 92 | backslash |
| Escape | Meaning |
|---|---|
\ddd...; | character with decimal code |
\0hhh...; | character with hexadecimal code |
Escape sequences such as \a
, \e
, \f
,
\t
, \v
are not supported because they are, or should
be, obsolete. Escape sequences such or \\
, \'
,
\"
are not supported because they complicate scanning and cause
visual confusion. A numerical escape is a backslash followed by digits, with an
optional semicolon terminator. It is used to represent a single character, using
its decimal character code. For example:
pi = '\960' any = '\0..\1114111'
If the first digit is zero, then the character code is in hexadecimal, using
a
to f
or A
to F
, e.g.
pi = '\03C0' any = '\0..\010ffff'
Numerical escape sequences are variable length. A decimal sequence ends when a non-digit is encountered, and a hex sequence ends when a non-hex-digit is encountered. If an escape sequence is to be followed by a digit or a semicolon, then it should be terminated by a semicolon, e.g.
pi3 = "\960;3" pi-semicolon = "\960;;"
By default, a parser produces an error message which points to the furthest position reached in the input text, other than in lookaheads, but which gives no details. For example, suppose this rule is being parsed:
sum = number ("+" number / "-" number)
Then a message like this might be produced for an incorrect operator:
Error on line 1: 40%2 ^
Markers can be added to parser rules, to describe the items which would have
allowed parsing to continue. A marker is a symbol consisting of the
#
character followed by a name. The name has the same form as an
identifier. In particular, it can be literal, as described in the literals
section. For example, suppose the rule above is changed to:
sum = number (#plus "+" number / #minus "-" number)
Then, for an incorrect operator, the expressions "+"
and "-"
both fail, so the error message produced becomes:
Error on line 1: expecting minus, plus 40%2 ^
When a marker is encountered, it is associated with the current position in the input. It records something that the parser is expecting at that point. If progress is made past that input position, the marker is cleared. When the parser encounters an error, the set of things that the parser was expecting at that point is reported. Duplicates are removed, for example suppose the rule is changed to:
sum = number (#operator "+" number / #operator "-" number)
Then the error message becomes:
Error on line 1: expecting operator 40%2 ^
During testing and development, markers are reported in alphabetical order. When a grammar is compiled, the order, and the text produced, can be customised.
One way to ensure that all the items which could possibly allow parsing to continue are reported is to write separate rules to describe low level features of a grammar involving primitive character matchers, i.e. strings, sets, etc., and begin each with a marker. For example, a parser for a programming language might contain rules such as:
plus = #operator "+" @ letter = #letter (Lu / Ll / Lt / Lm / Lo) number = #number ('0'..'9')+ @read newline = #newline '\r'? '\n' @ end = #end <>
The plus
rule specifies that the plus sign is to be described as
an operator in error messages. The letter
rule applies an error
marker to a choice of Unicode categories, to avoid having to attach a marker to
each one individually.
Actions allow a parser to operate on values or data structures, using a
stack, to produce an output. An action is a symbol which consists of the
@
character followed by a number followed by a name. If there is no
number, it is assumed to be zero. The name follows the same rules as an
identifier. In particular, it can be a literal name, as discussed in the section
on literals. For example:
sum = term (plus term @2add)*
Suppose that the term
rule pushes a single item onto the stack,
and the plus
rule doesn't affect the stack. The @2add
symbol in the sum
rule indicates that two items should be popped
off the stack, the add
action should be performed, which creates a
new item, and the new item should be pushed onto the stack. A parser as a whole
ends with a single item on the stack, which is the output from the parsing
process.
Defining an action as a stack-based operation allows it to be expressed as a
self-contained symbol at a specific point in a grammar. That in turn allows
actions to take part in grammar transformations which move actions away from
their arguments. For example, the above rule can be transformed to these rules,
where the two arguments to the add
action are separated:
sum = term more* more = plus term @2add
The stack is provided and manipulated by external code when a parser is
generated from the grammar. An action symbol such as @2add
is
translated into the execution of a fragment of external code. The parser could
be part of a calculator, in which case the add
action might add two
numbers. Alternatively, the parser might become part of a compiler, in which
case the add
action might combine two expression trees into a
larger tree. When executing a grammar symbolically for testing, the name of the
action is simply printed out.
An action has access to the characters or tokens from the input which have been matched since the previous action. For example:
number = digit+ @read
The action @read
creates a new item from the digits which
have just been matched, and pushes it onto the stack. There is a further
convention which allows matched characters to be discarded. For example:
spaces = ' '+ @
An @
sign on its own causes any recently matched characters (or
tokens) to be discarded by the parser, without any external code being
executed.
Recently matched characters are available to an action, no matter what arity
it has. However, for an action like @2add
which combines output
items, it is common to ignore them. If there are any such characters, and they
are ignored by an action, they are implicitly discarded. Also, a discard with
non-zero arity such as @2
is allowed. This discards two output
items, as well as any outstanding matched characters.
There are severe consistency restrictions on actions. Every expression or
rule must produce or consume a fixed number of output items. Each alternative in
a choice must create or consume the same number of output items. Within a
repetition, i.e. x*
or x+
or x?
, the
inner expression x
must have no net effect on the number of output
items.
The compensation for these severe restrictions is that Pecan can carry out strong consistency checks on grammars, ensuring that every expression produces a fixed and known number of output items overall, and needs a known number of items to be on the stack before it is executed.
The first rule in a grammar must produce a single output item overall, and must not need any items on the stack before execution, so that it cannot cause the output stack to underflow. However, if this is not the case, the error is reported only when attempting to generate a parser from the grammar. That means, during development and testing, a grammar with no actions is legal, and also any self-contained fragment of a grammar is legal.
Scanners are normally thought of as producing a sequence of tokens. But in Pecan, even a scanner must produce a fixed number of output items. A scanner can be defined like this:
scan = @tokens token+ end token = number @1number / id @1id / ...
The @tokens
action creates an output item representing the list
or array of tokens to be generated, initially empty. Each action such as
@1number
takes the recently matched characters, creates a token
from them, and adds it to the list. The list is the only output from the
scanner.
In a token-based parser, there are often variable-length sequences, which need to be dealt with in a similar way. For example, a comma-separated list of identifiers can be expressed by:
ids = @list id @2id ("," id @2id)* @1end
The id
rule is assumed to push a single item onto the output
stack. The @list
action creates an empty list. The
@2id
action pops the list and most recent id, adds the id to the
list, and pushes the resulting list back on the stack. The @1end
action does anything necessary to finalize the list.
The external code in a generated parser may choose a different implementation
with the same overall effect. For example, @list
may mark a
position in the output stack, @2id
may do nothing, so that ids
accumulate on the stack, and @1end
may use the marked stack
position to create an array out of the accumulated ids. Alternatively,
@list
could create a linked list, each subsequent
@2id
could chain the next id onto the end of the list, and
@1end
could do nothing.
Techniques like this for handling variable-length lists can easily lead to a left hand alternative which begins with an action, for example:
@a x / y
The action @a
is performed whether or not x
succeeds. This is not completely intuitive, and probably not what was intended
since @a (x / y)
would express the intention better. This issue is
not reported during development, so that transformations remain valid, but is
reported when compilation is requested. A similar situation arises with error
markers:
#m x / y
However, the fact that the marker takes effect even if x
fails
is normal, so that if parsing as a whole fails without progressing beyond this
point, the marker is reported as one of the things expected.
Support is provided for parsers where the input consists of tokens produced by a separate scanner. The input is thought of as an array of tokens instead of an array of characters.
A tag is represented as a symbol consisting of the %
character
followed by a name. The name has the same form as an identifier. In particular,
it can be literal, as described in the next section. Each tag represents a
specific kind of token. For example, a token-based parser for a simple
calculator with no brackets might look like this:
sum = term (%plus term @2add / %minus term @2subtract)* end term = number (%times number @2multiply / %over number @2divide)* number = %int @read end = <>
In this case, the input is an array of tokens with tags %int
,
%plus
, %minus
, %times
or
%over
.
In token-based parsers, text matching notations are not allowed, except for
''
, ""
and <>
.
A tag represents a call to an external function to find the type of the current token. This allows a limited form of context dependence while parsing. For example, it is well known that parsing of the C language requires typedef names to be recognised separately from other identifiers, and that typedef constructs have to be parsed to provide that information. This can be achieved by classifying both types of token as identifiers in the scanner. Then, in the parser, the actions carry out sufficient symbol table construction to represent typedef constructs. Then, when the external tag function is called, it uses the symbol table to decide whether to return an identifier tag or a typedef tag.
The names used in identifiers, actions, markers and tags normally consist of a letter followed by letters, digits, hyphens or underscores. Literal names can be used as an alternative. A literal name consists of one or more characters inside backquotes. The escape sequences described earlier are also available. This helps to make grammars more readable when a separate scanner and parser are being designed. For example, a scanner might contain:
ge = ">=" @1`>=`
Each character in a literal name is automatically converted to an
alphanumeric form, e.g. @1`>=`
is equivalent to
@1GtEq
. Then, when the scanner is compiled, the action name
GtEq
is a valid identifier or constant in the target programming
language. If action names are used as token tags, this notation avoids the need
to invent tag names for tokens with fixed spellings.
In the corresponding token-based parser, the tag name produced can be matched by a tag with the same literal name. For example:
ge = #op %`>=`
The same translation to alphanumeric form is used, so the tag
%`>=`
is equivalent to %GtEq
and the compiled parser
thus matches up with the compiled scanner.
To improve the readability of a token-based parser further, e.g. so that it corresponds closely to a published grammar, literal names can also be used for identifiers. For example:
comparison = expression `>=` expression ... `>=` = #op %`>=`
For an alphanumeric literal, the quotes have no effect, so `int`
is equivalent to int
, making the quotes unnecessary, but using
`int`
may still be desirable to emphasize that the identifier
stands for a keyword token with a fixed spelling. Whether backquotes are used or
not, hyphens are translated to camel case to make it more
likely that the result is a valid identifier in the target programming language.
For example, a tag %string-literal
is translated to
stringLiteral
.
When a grammar is compiled to produce a parser, custom adjustments can be specified for each different type of name, to prevent name clashes. The same adjustment should be specified for actions in the scanner as for tags in the parser, so that the generated tag names correspond.
During development of a grammar, testing can be carried out by symbolic execution without having to generate a parser. This is done by typing a command of the form:
pecan [-t | -trace] [line] testfile
The test file contains the tests to be carried out. The -trace
option switches on tracing, so that the individual steps taken during parsing
are displayed. If a line number is given, only the single test that starts on
that line of the test file is executed.
A test file contains a number of sections separated by lines consisting of ten or more equal signs. If a section contains a line of ten or more minus signs as a separator, then it is a test with sample input and expected output. If a section has no separator, it is a grammar or self-contained grammar fragment which is used for subsequent tests, until another grammar is given. For example:
// Match one digit number = ("0".."9") @read ========== 2 ---------- read 2 ========== 42 ---------- read 4 ========== // Match any number of digits number = ("0".."9") @read ========== 42 ---------- read 42
The first section of this file sets up a grammar, then there are two tests using that grammar, then a new grammar is given, then there is a final test using the second grammar.
The output from running a test using a given grammar and sample input is a list of the actions that would be performed by a parser generated from the grammar. If the input is text, the characters matched since the previous action or discard are displayed.
For a token-based grammar, the input consists of a sequence of tag names separated by white space:
// Match a list of numbers. list = %number @read (%comma %number @read @2and)* ========== number comma number comma number ---------- read read and read and
When a test fails, its line number is reported in the error message. That line number can then be used to re-run the testing, but picking out only that one test to be performed, perhaps with tracing:
pecan tests.txt Fail test on line 24 of tests.txt: ---------- Expected ---------- ... ---------- Actual ---------- ... pecan -trace 24 tests.txt ...
A grammar in a test file can have an inclusion. For example, a file
tests.txt
might start with:
{grammar.txt} ========== ...
This is the usual way to arrange for a grammar to be in one file,
grammar.txt
in this case, and the tests in another. A test file
might also begin with something like:
start = expression <> {expressions.txt} statement = ... ========== ...
In this case, the file expressions.txt
contains one module of a
multi-module grammar. The start
rule specifies that it is the
expression
rule that is under test, and <>
is used
to ensure that the expression
rule parses all of the input supplied
in each test. The statement
rule provides a simplified version of a
rule from another module, which the file expressions.txt
makes a
forward reference to.
If a grammar fragment consists of a single line which is an inclusion, then the included file can be another test file, rather than just a grammar, allowing tests to be grouped:
{group1.txt} ========== {group2.txt} ========== ...
There is no conflict between a filename representing a grammar and one representing a subfile of tests. That is because a grammar file is equivalent to a test file which sets up a grammar, but contains no tests.
Test files are assumed to use the UTF-8 encoding. They are normalized to
avoid common visual ambiguity problems, by changing all line endings to
\n
, removing trailing spaces at the ends of lines, and removing
trailing blank lines at the very end of the test file. The escape sequences
described earlier are recognised anywhere in the test input, and can be used to
express control characters and Unicode characters beyond ASCII in the output. To
allow edge cases to be tested, there is a further convention that if an input
line ends in an escape sequence, the newline is cancelled. For example:
========== Line one\r Line two \n ---------- ...
The first input line ends in a carriage return instead of a line feed, and the second input line has a trailing space.
A number of checks are performed on a grammar which help to ensure consistency. Some obvious checks are done first, such as syntax checking of the grammar, checking that each rule name is defined exactly once, and checking that no rule name clashes with a category name.
A grammar is checked to see if it represents a text parser or a token parser.
A text parser must contain no tags. A token parser must not contain text
matchers, i.e. strings, splitters, sets, ranges or numbers, with the exception
of ""
or ''
or <>
.
There are also checks on sets and ranges. Sets must contain distinct characters, and a range must be non-empty.
Many parsing expressions are equivalent, which considerably reduces the number of cases that need to be discussed. For example:
. ≡ '\0..\1114111' '\32' ≡ ' ' 'a' ≡ "a" "ab" ≡ ['a' 'b'] 'ab' ≡ 'a' / 'b' 'a..z' ≡ 'a' / ... / 'z' Ll ≡ 'a' / ... / 'z' / ... x? ≡ x / "" x* ≡ xs where xs = (x xs)? x+ ≡ x x* [x] ≡ x& x x& ≡ x!! '' ≡ ""! <b...> ≡ <> / '\0..a'& / ('b' <...>)& <> ≡ .!
The core features remaining are:
id = x
rules""
the empty string (always succeeds)"x"
single charactersx/y
choicesx y
sequencesx!
the 'not' lookahead%a
tags@2a, @a, @
actions#a
markers
The main checks are to make sure that there is no left recursion, and that output items are handled consistently.
Pecan checks that the grammar contains no infinite loops caused by left recursion. The simplest example is where a rule mentions its own name at the start of its right hand side, or at the start of one of its alternatives:
sum = sum "+" term / term
In a Pecan grammar, a rule of this form leads to an immediate infinite loop, and so is reported as an error. Indirect left recursion is also detected. That is where two or more rules mention each other at the beginning:
expression1 = expression2 ... expression2 = expression1 ...
Less obvious cases of left recursion are also detected, e.g.
statement = label* statement
Although statement
does not mention itself right at the
beginning, the expression label*
may succeed without any input
being matched, and therefore an infinite loop ensues.
To implement the checks, four boolean properties of expressions
SP
, SN
, FP
, FN
are
calculated for each expression. The SP
, SN
properties
mean the expression can succeed with or without progress being made in the
input, and FP
, FN
mean that an expression can fail,
with or without progress. These are very similar to the properties used in
the analysis of PEG grammars, though there FP
and FN
are not distinguished.
As well as the equivalences already mentioned, there are further parsing expressions which are equivalent from the point of view of success or failure, and progress or not:
%a ≡ "a" @2a, @a, @ ≡ "" #a ≡ ""
The way the properties are calculated for the remaining features of grammars
(using &
for 'and' and |
for 'or', with
&
binding tighter, and using def(id)
for the right
hand expression of a rule for identifier id
are:
SN(id) = SN(def(id)) SP(id) = SP(def(id)) FN(id) = FN(def(id)) FP(id) = FP(def(id)) SN("") = true SP("") = false FP("") = false FN("") = false SP("a") = true FN("a") = true SN("a") = false FP("a") = false SN(x y) = SN(x) & SN(y) SP(x y) = SP(x) & SP(y) | SP(x) & SN(y) | SN(x) & SP(y) FN(x y) = FN(x) | SN(x) & FN(y) FP(x y) = FP(x) | SN(x) & FP(y) | SP(x) & FN(y) | SP(x) & FP(y) SN(x/y) = SN(x) | FN(x) & SN(y) SP(x/y) = SP(x) | FN(x) & SP(y) FN(x/y) = FN(x) & FN(y) FP(x/y) = FP(x) | FN(x) & FP(y) SN(x!) = FN(x) | FP(x) SP(x!) = false FN(x!) = SN(x) | SP(x) FP(x!) = false
Because these rules are themselves recursive, fixed point iteration is used,
i.e. the values are calculated repeatedly until they don't change. If all the
values are set to false
at the start, the only possible changes are
from false
to true
, so the iteration terminates.
Once these values are known, a further boolean property, WF
is
calculated to check that the grammar is well formed. The WF
property is calculated (using ~
for 'not') by:
WF(id) = WF(def(id)) WF("") = true WF("a") = true WF(x y) = WF(x) & (~SN(x) | WF(y)) WF(x / y) = WF(x) & WF(y) WF(x!) = WF(x)
If WF
turns out to be false for any expression, that expression
is reported as an error because it contains left recursion.
Actions are assumed to treat output items in a stack-like manner. Restrictive
checks are made to guarantee consistent handling of output items. The arity of
each action has to be specified, and has to be consistent each time the action
appears. For example if a grammar contains both @1add
and
@2add
, that is reported as an error. The arities are used to check
that each expression in the grammar produces a fixed, known number of output
items.
The net overall number of items added to the stack, possibly negative, is calculated for each expression in the grammar.
Both alternatives in a choice expression must have the same net effect. For example, this rule causes an error:
token = ('0..9')+ @token / ' '+
The first alternative adds one item to the stack, but the second adds nothing. On the other hand, this rule is legal:
token = ('0..9')+ @1token / ' '+
The @1token
action pops an item from the stack, presumably a
list of tokens, and pushes one item back on the stack, presumably the updated
list. It thus has zero net effect. Since both alternatives now have a zero net
effect, the token
rule itself can be deduced as having a zero net
effect.
 For example, suppose the grammar contains:
tokens = (('0..9')+ @token)*
The inner expression causes one output item to be pushed on the stack. This
is reported as an error, because the tokens
rule as a whole pushes
an unknown number of items onto the stack. On the other hand, this definition is
allowed:
tokens = (('0..9')+ @1token)*
The inner expression pops a previous list item, adds a token to it, and
pushes the updated list onto the stack. As a result, it has a zero net effect.
It can be repeated any number of times, still with a zero net effect, and so the
tokens
rule can be deduced to have zero net effect.
As well as repeated expressions, recursion is also restricted so that the number of output items produced is fixed. For example:
x = 'a' x @a
Here, the number of items pushed onto the stack depends on the number of
times x
calls itself recursively. So this is reported as an
error.
A further check is related to stack underflow. For each expression, the
number of items which need to be on the stack when the expression is executed is
calculated. For example, the expression ('0..9')+ @1token
needs one
item to be on the stack. There are situations where the needed number can't be
calculated, for example:
x = 'a' / 'b' @2c x @d
Every time x
calls itself recursively, one more item is needed
on the stack, even though the net effect of x
is zero. Such a
situation is reported as an error.
There are a few checks that are not made until a grammar is compiled. One is that the first rule in the grammar produces exactly one output item. For example:
first = "a" @b @c
This produces two items, so is reported as an error. A second check is that the first rule needs no items to be on the stack before it starts. For example:
first = "a" @1b @c
Although overall this produces one output item, it needs an output item to be on the stack before parsing starts. The check ensures that parsing of the entire grammar can never cause a stack underflow.
These two issues are not reported during development of a grammar, so that a grammar with no actions, or a self-contained fragment of a grammar, are legal and can be tested.
A further check is that any left hand alternative of a choice can fail with no progress. For example:
x = "" / "a"
The first alternative can't fail, so the second alternative is inaccessible, i.e. parsing can never reach it. Another check is that a left hand alternative doesn't start with an action. For example:
x = @a "b" / y
This is to guard against ambiguity. The action @a
is executed
whether or not the first alternative succeeds, which is probably not what is
intended. If it is what is intended, it should be rewritten as:
x = @a ("b" / y)
These issues concerning choices are not reported during development of a grammar, because they can temporarily arise naturally during transformations.
A grammar can be compiled to a set of recursive functions, in almost any desired target programming language. A grammar is compiled using a command of the form:
pecan grammar -c programfile
The option -c programfile
specifies a template program file. The
program file must already exist, and it must contain a placeholder such as:
// <pecan ... // > ... // </pecan>
The placeholder begins with a commented out open tag <pecan>
,
with attributes as described below, and ends with a commented out close tag
</pecan>
. Lines in between the two tags, if any, are removed,
and the result of compiling the grammar is inserted in their place. That means
compiling can be carried out repeatedly using the same program file.
An example template program in the C language, with two supporting data files, is:
Very few restrictions are placed on the target programming language when
compiling. The main assumption is that the language has two binary and/or
operators which are guaranteed to use short-circuit evaluation, i.e. they do not
evaluate their right hand arguments unnecessarily. In many languages, the
symbols &&
and ||
are suitable. The
&&
operator does exactly what is required for a sequence
x y
, evaluating x
and then, only if x
succeeds, continuing with y
. A choice x / y
is
complicated by the need to test whether x
has progressed or not
before deciding whether to try y
instead. So, in general, x /
y
is compiled into something like:
alt((go() && tx) || (ok() && ty))
Here tx
, ty
represent the translations of
x
, y
into boolean expressions. The go
function pushes the current input position onto a stack before tx
is executed, the ok
function checks for progress, and the
alt
function pops the saved position off the stack after the choice
has been completed. The go
function is also used in the compilation
of other Pecan features. For example, an expression x&
is
compiled to:
has(go() && tx)
The has
function pops the position saved by go
and
backtracks to it, before returning the result of tx
.
This general approach, using a background stack for progress checking, allows
every parsing expression to be compiled into a boolean expression, with only the
&&
and ||
operators being used to combine
expressions.
The open tag <pecan...>
of the placeholder includes
attributes. The attributes specify details of how to generate functions in the
target language for the given application:
// <pecan // comment = "// %s" // declare = "bool %s(parser *p);" // define = "bool %s(parser *p) { %n return %r; %n}" // call = "%s(p)" // escape1 = "\%3o" // escape2 = "\u%4x" // escape4 = "\U%8x" // > ... // </pecan>
This example is suitable for C as a target language, where a pointer to a parsing state is to be passed to every parsing function. Each attribute is on a separate line, and consists of one of the attribute names described below, followed by an equal sign followed by a string in single or double quotes. The whole attribute may be preceded or followed by comment characters. Each attribute string is a format string in a printf style specifying the text to be generated for a specific Pecan feature.
In a format string, the percent character is the only special character, used for specifiers. There are no backslash escape conventions. Each specifier determines what to extract and print from the current construct.
The specifier %s
indicates that a string or name should be
printed. Identifier names with hyphens are translated to camel case and literal names
are translated as described earlier. The specifiers %l
,
%r
indicate that a left or right subexpression is to be compiled
and printed. The specifier %n
indicates that if an expression does
not fit on the current line, a newline and indent is printed. A space before
%n
is deleted if the newline is printed. A space after
%n
increases the indent temporarily if the newline is printed, or
is deleted otherwise. A character can be printed directly using %c
,
or its integer code can be printed using %d
for decimal,
%o
for octal, or %x
for hexadecimal. A fixed number of
digits can be specified for %d
, %o
or %x
,
e.g. %4x
, with leading zeros being added where necessary. When
printing a range, two character or numeric specifiers are used to refer to the
low and high characters, e.g. the format for a range might be
"range('%c','%c')"
.
The attributes that can be specified are:
declare:
the format for generating a forward
declaration of a function. The format string might be "bool %s();"
for example. The default is
""
so that no forward declarations are generated.
comment:
the format for generating each line of a
comment before each function generated. The format string might be "// %s"
or "/* %s */"
for example. The %s
refers to the source text of the Pecan rule that the function corresponds to.
The default is ""
so that no comments are generated.
define:
the format for a function definition
generated from a rule id = e
, for example "bool %s() { %n return %r; %n}"
. The specifier
%s
refers to the identifier name, and %r
to the right
hand side expression. There is no default.
tab
: the unit for indenting. The default is " "
(two spaces).
and, or, true, false:
the
formats for the boolean operators and constants. The defaults are "&&"
, "||"
, "true"
and
"false"
.
escape1, escape2, escape4:
formats to
change the way string or character literals are printed in calls to
text
, set
, split
or range
calls, by printing escape sequences instead of UTF-8. The escape1 format
is for one-byte control characters, escape2 is for two-byte Unicode
characters, and escape4 is for four-byte Unicode characters. For example,
formats "\%3o"
, "\u%4x"
, "\U%8x"
are
suitable for the C language. (Note that \x%2x
in C is problematic
if a digit follows.) With these formats, a Pecan string
"abπ"
is translated as string("ab\u03c0")
. The
defaults are ""
, which means that all characters are written
verbatim into the program.
call:
the format for making a call to any parsing
function. For example, %s(p)
could be used if an argument
p
is to be passed to every call. The default is
%s()
.
id:
the format for generating a call to represent the
occurrence of an identifier. This can be used to adjust identifier names
independently of other names. For example, an id format "P%s(p)"
would cause an occurrence of an identifier term
to be compiled as
Pterm(p)
. The default is to use the call format.
act, act0, ...:
the format for printing
actions, and formats to override it for specific arities. The default for the
act format is act%d(%s)
, adjusted according to the call format. The
specifier %d
refers to the arity and %s
refers to the
name of the action. The defaults for act0
, act1
...
are to use act
.
go, ok, alt, opt, see,
has, not, tag, eot, string, set,
split, range, cat, mark, drop:
These
are supporting functions for the various Pecan features. Each can be changed
individually, if desired. The default in each case is to adapt the call format
appropriately. For example if the call format is %s(p)
, then the
defaults for go
, opt
, tag
,
set
and range
are go(p)
,
opt(p,%l)
, tag(p,%s)
, set(p,"%s")
and
range(p,'%c','%c')
. These can be used to change individual function
names or their calls, or to adjust tag names or marker names independently of
other names, e.g. if tag
is set to tag(T%s)
then a
Pecan tag %id
is compiled to tag(Tid)
.
These format strings allow compilation to be adapted to different languages
or applications. The default act format "act%d(%s)"
treats action
names as enumerated constants. Instead, the act format could be specified
as:
// <pecan // ... // act = "%s()" // ... // >
Then each action has its own function with implicit arity. Action functions of this kind would need access to the parsing state and would be responsible for stack handling, and for marking matched characters as used. An alternative is to define:
// <pecan // ... // act = "push(%s(text(),pop(%d)))" // ... // >
The text()
call forms a string from the recently matched
characters and marks them as used, the pop(n)
call pops
n
output items from the stack and returns them as an array, and the
push
call pushes the output item returned from the action function
onto the stack (returning true
). This means that the action
functions no longer need access to the parsing state. To go further, the formats
for actions of each arity could be specified as:
// <pecan // ... // act0 = "push(0,%s(text()))" // act1 = "push(1,%s(top(0)))" // act2 = "push(2,%s(top(1),top(0)))" // ... // >
Now each action function is passed only what it needs. The
text()
call forms a string from the recently matched characters,
top(n)
returns the n'th item from the top of the output stack, and
push(n,x)
pushes x
onto the output stack to replace
the top n items and marks any recently matched characters as used.
Instead of compiling a grammar to recursive functions, a grammar can instead be translated into an interpretive bytecode. This is suitable for dynamic situations. For example, suppose that a programmer's editor or IDE needs a scanner or parser for each of a large number of different programming languages. It may be desirable to load up the scanner or parser on demand for any specific language, by reading in a bytecode file and running a generic bytecode interpreter.
A grammar is compiled into bytecode using a command of the form:
pecan grammar -b file
The option -b file
specifies the name of a binary file into
which to write the bytecode. As well as creating the file, the command prints
out the integer values used for opcodes, actions, markers, tags and/or Unicode
categories used in the bytecode. For example:
pecan grammar.txt -b out.bin Opcodes: {ACT=0, AND=1, ARITY=2, BACK=3, BOTH=4, CAT=5, DO=6, DROP=7, EITHER=8, EOT=9, GO=10, HAS=11, HIGH=12, LOOK=13, LOW=14, MANY=15, MARK=16, MAYBE=17, NOT=18, ONE=19, OR=20, POINT=21, SEE=22, SET=23, SPLIT=24, START=25, STOP=26, STRING=27, TAG=28} Actions: {add=0, divide=1, multiply=2, read=3, subtract=4} Markers: {bracket=0, integer=1, newline=2, operator=3} Categories: {Cc=0, Cf=1, Cn=2, Co=3, Cs=4, Ll=5, Lm=6, Lo=7, Lt=8, Lu=9, Mc=10, Me=11, Mn=12, Nd=13, Nl=14, No=15, Pc=16, Pd=17, Pe=18, Pf=19, Pi=20, Po=21, Ps=22, Sc=23, Sk=24, Sm=25, So=26, Zl=27, Zp=28, Zs=29} Bytecode file sum.bin written.
The names of each type are put into alphabetical order and sequence numbers are assigned. The information printed out can be used to set up or confirm the values of enumerated constants in the interpreter. An example interpreter in the C language is:
An interpreter can be constructed by taking the example interpreter provided, translating it into the desired programming language, and adapting it to a particular application by customising constants and functions as appropriate.
The bytecode produced from a grammar is a fairly simple flattening of the parse tree for the grammar. A rule is translated into a bytecode sequence of the form:
{id = x} = START +nx {x} STOP
In these descriptions, the notation {x}
means "the bytecode
sequence generated for expression x" and nx
stands for the number
of bytes in {x}
. The instruction START +nx
is a
sequence of one or more bytes with opcode START
and operand
nx
. For small values of nx
, the operand may be
included in the opcode byte. For larger values, one or more extension bytes may
be needed. The STOP
opcode needs no operand.
The START
opcode creates a call to {x}
, setting up
the address of STOP
as the return address. The STOP
instruction ends parsing. The operand nx
to START
can
be thought of as a relative offset in the code to the STOP
instruction.
START
and STOP
opcodes are generated for every
rule, even though they are only executed once for the overall call to the
parser. This is so that any rule can be used as an entry point, if desired. The
bytecode can be scanned, skipping the body {x}
of each rule using
the number nx
, to find the start of the next rule.
{id} = GO +px {id} = BACK -px
When the name id
of a rule such as id = x
is used
elsewhere in the grammar, it is translated using GO
or
BACK
. The operand of GO
is a relative offset to the
address px
in the code of the body {x}
of the relevant
rule. The BACK
opcode is used, with a positive argument, when the
offset is negative.
{"a"} = STRING 1 97 {97} = STRING 1 97 {128} = STRING 2 194 128 {"ab"} = STRING 2 97 98 {""} = STRING 0 {"π"} = STRING 2 207 128 {"aπ"} = STRING 3 97 207 128 {'π'} = STRING 2 207 128 {<a>} = SPLIT 1 97 {<ab>} = SPLIT 2 97 98 {'a..z'} = LOW 1 97 HIGH 1 122 {'α..ω'} = LOW 2 206 177 HIGH 2 207 137 {''} = SET 0 {'a'} = SET 1 97 {'ab'} = SET 2 97 98 {'αβ'} = SET 4 206 177 206 178
A character matching opcode has a count as an operand, and is followed by
that number of bytes in UTF-8 format. For opcodes other than SET
, a
byte sequence containing characters of mixed UTF-8 lengths causes no problem,
because UTF-8 text can be compared byte by byte, without taking account of
character boundaries. With the SET
opcode, a sequence with mixed
UTF-8 byte lengths cannot be handled byte by byte, but the first byte of each
character can be used to find the character's length.
{@a} = ACT a {@2a} = ARITY 2 ACT a {@} = DROP 0 {@2} = DROP 2
An action is translated using the ACT
opcode. Actions and error
markers are switched off during has x&
or not x!
expressions. An integer in the interpreter keeps track of the depth of nesting
of lookahead constructs, and actions are only performed if the integer is zero.
For see [x]
expressions, x
is executed once with
actions and markers switched off, then again with them switched back on, in line
with the identity [x] ≡ x& x
.
{#e} = MARK e {%id} = TAG id
Error markers, signalled by the MARK
opcode, are collected as a
set, and cleared whenever a new marker is found further on in the input. Tags
are used only in token-based parsers. They cause a call to external code to find
the tag of a particular token.
{Nd} = CAT Nd
A category is translated using the CAT
opcode. The target
programming language may not have a facility for finding the category of a
character. Even if it does, the category information may vary according to the
version of the language. For stable category information, Pecan provides a
two-stage lookup table in the two files table1.bin
and
table2.bin
which may be read into memory by the target
language.
{x/y} = EITHER +nx {x} OR {y} {x y} = BOTH +nx {x} AND {y}
The EITHER
opcode initializes a choice, and OR
checks what happens after {x}
to decide whether or not to continue
with {y}
. Similarly, the BOTH
and AND
opcodes handle a sequence. The EITHER
or BOTH
opcode
can be thought of as causing a call to {x}
returning to
OR
or AND
, which may cause a tail-call to
{y}
.
{x?} = MAYBE ONE {x} {x*} = MAYBE MANY {x} {x+} = DO AND MAYBE MANY {x} {[x]} = LOOK SEE {x} {x&} = LOOK HAS {x} {x!} = LOOK NOT {x}
The MAYBE
opcode initializes a repetition, then causes a call to
{x}
, returning to ONE
or MANY
. The
ONE
opcode converts the result of {x}
into the result
of x?
. The MANY
opcode is similarly executed after
{x}
and checks the result of {x}
to decide whether or
not to call it again. The opcode sequence used here, with the termination check
before the code for {x}
, avoids the need for an nx
operand. The code for x+
is equivalent to the code for x
x*
, except that the DO
opcode avoids the need for a second
copy of {x}
by jumping forwards to {x}
, and arranging
for the call to return to AND
. The LOOK
opcode
initializes any of the lookahead constructs, arranging to return to
SEE
or HAS
or NOT
which sorts out the
result.
To give a concrete example, suppose a grammar consists of the rule:
digit = '0..9' @read
The bytecode sequence generated from this has the form:
START +5 LOW 1 '0' HIGH 1 '9' ACT 0 STOP
The sequence might also be represented in a form resembling an assembly language:
0: START 7 2: LOW 1 '0' 4: HIGH 1 '9' 6: ACT 0 7: STOP
In this form, each line represents one instruction, preceded by its address
in the bytecode. The offset operand +5
to the START
instruction is displayed as an actual bytecode address 7
. The
opcodes LOW
, HIGH
, ACT
have operands
small enough to be included in the opcode byte.
Further details of how instructions are encoded and what each opcode does can be gleaned from an interpreter program and its comments.
The Pecan grammar language is intended to be sufficiently simple and precise to support equational transforms. At present, such transforms are carried out manually and informally on grammars, but it is possible to imagine a theory of transforms being developed more formally and used to develop and justify automatic optimisations, or to build an assistant which would suggest and check user-driven transforms while developing grammars. Equations such as these can be used:
(x y) z == x (y z) (x / y) / z == x / (y / z) x+ == x x* x* = (x+)? x? = x / "" [[x] y] z == [x y] z [x y] z / [x u] v == [x] ([y] z / [u] v) (x / y) z = x z / y z
Care has to be taken, because not all 'obvious' equations hold. For example,
x (y / z)
is not equivalent to x y / x z
because if
x
succeeds, in the first case the parser is free to make the choice
between y
and z
, but in the second case it is already
committed to y
. Also x / y
and y / x
are
not equivalent. However, they are equivalent if it can be established that
x
and y
begin differently. In these equations, actions
and error markers are included, and the transformed expression has precisely the
same output effect and error handling properties as the original.
The previous version of Pecan was 0.4. Changes in version 1.0 are:
<abc>
and end notation
<>
have been added


We will cater your special events!
Weddings, Christmas parties, baby showers...the list goes on!
Just let us know what you are looking for so we can best serve your needs.
715-634-2785 or 1-800-40-FUDGE


Twilio Client iOS Changes
1.2.7 (Nov. 23, 2015)
Bug Fixes
- CLIENT-1690 - Fixes a bug where an application was not able to receive presence events after calling
unlisten
thenlisten
sequentially onTCDevice
. - CLIENT-1695 - Initializing or updating a
TCDevice
instance with anil
or empty capability token string will now trigger thedevice:didStopListeningForIncomingConnections:
delegate callback. - CLIENT-1812 - The SDK will no longer print log messages for temporary SIP registration redirects.
- CLIENT-1878 - Fixes a crash when initializing or updating a
TCDevice
instance.
1.2.6 (Nov. 9, 2015)
Bug Fixes
- CLIENT-1688 - The SDK now gracefully handles audio interruptions from incoming phone calls and other audio events. The audio of a Twilio Client call will resume after an interruption ends.
- CLIENT-1950 - The SDK automatically rejects pending incoming connections upon network reachability change events.
API Changes
- CLIENT-2038 - New API
setMetricsEnabled:(BOOL)enabled
added inTwilioClient
to enable/disable the collection and transmission to Twilio of call quality analytics. This feature is enabled by default.
1.2.5 (Sep. 3, 2015)
Bug Fixes
- CLIENT-1878 -
TCDevice
no longer automatically reconnects to Twilio following a disconnection due to bad network connectivity. The previous behavior produced a crash when the application developer simultaneously attempted to reconnect at thedevice:didStopListeningForIncomingConnections:
delegate callback.
1.2.4 (Aug. 13, 2015)
Bug Fixes
- CLIENT-1878 - Fix crash when multiple
TCDevice
initializations or updates are made under bad network connectivity. - CLIENT-1823 - Twilio Client crashes when
TCDevice
set tonil
. - CLIENT-1928 - Fix crash when phone is in airplane mode.
- CLIENT-1915 - Convert BasicPhone sample app to ARC.
1.2.3 (Mar. 19, 2015)
Bug Fixes
- MSDK-181 - Fix crash when placing a call before registration completes.
- MSDK-305 - Remove non-referenced libraries from sample projects.
- MSDK-309 - Suppress warning message about wildcard certificates.
- MSDK-388 - Fix crash on
TCPresenceEvent
. - MSDK-477 - Fix rare registration failure with redirect.
1.2.2 (Jan. 29, 2015)
API Changes
- MSDK-87 - New API to obtain version of iOS SDK.
Bug Fixes
- MSDK-8 -
TCDevice
state becomesTCDeviceStateOffline
whenever its capability token expires. - MSDK-77 -
TCConnectionState
enum is now accessible from Swift. - MSDK-93 - The SDK now includes separate libraries for OpenSSL.
- MSDK-98 - The SDK no longer crashes when initializing
TCCommandHandler
in iOS 7.0 and lower. - MSDK-100 - Corrected a crash that could occasionally occur when un-registering a
TCDevice
by calling-unlisten
or due to capability token expiration. - MSDK-101, MSDK-102, MSDK-146, MSDK-181 and MSDK-183 - A number of crashes that could occur when calling
[TCDevice connect]
have been corrected. - MSDK-106 - The SDK no longer pauses music when
[TCDevice initWithCapabilityToken]
is called. - MSDK-184 - The SDK now uses OpenSSL v1.0.1k.
1.2.1 (Dec. 18, 2014)
Bug Fixes
- MSDK-42 - Eliminated "duplicate symbol" error loading lib in TwilioSDK 1.2.
- MSDK-47 - Eliminated a rare crash when handling a 302 redirect response from Twilio.
- MSDK-56 - TwilioSDK no longer holds onto
TCConnection
objects. - MSDK-58 - Fixed a problem where
didReceiveIncomingConnection
did not work as expected when handling multipleTCDevice
objects. - MSDK-76 - Eliminated a crash caused by accessing
pjlib
in an unknown/external thread.
1.2.0 (Nov. 25, 2014)
Initial 1.2 release.
Support for Twilio’s Global Low Latency Routing
Twilio Client for iOS now takes advantage of Twilio’s Global Low Latency (GLL) routing to further improve call quality. Media for all Twilio Client calls is routed to the Twilio data center geographically nearest to the user, significantly reducing call latency.
Support for arm64
Twilio Client for iOS can now target the 64-bit runtime, improving the performance of your Twilio Client application.
Symbol Prefixing
All internal symbols are now prefixed with twilio_ to avoid conflicts with other dependencies.
Richer Debug Logging
We’ve made it easier to find and resolve issues in your Twilio Client iOS application with more detailed logging.
[[TwilioClient sharedInstance] setLogLevel:TC_LOG_DEBUG];
Available log levels in order of verbosity: TC_LOG_OFF
, TC_LOG_ERROR
, TC_LOG_WARN
, TC_LOG_INFO
, TC_LOG_DEBUG
, TC_LOG_VERBOSE
.
Call Sid Availability
Call Sid is available for outgoing calls as well.
Improved Sample Applications
We have improved both BasicPhone and Quickstart sample applications. Server backend can be simply installed to your Heroku account from https://github.com/twilio/mobile-quickstart.
Supported iOS Releases
- iOS 6.0+
- iOS 7.0+
- iOS 8.0+
Supported iOS Devices
- iPhone 4S and later (running iOS 6 and later)
- iPad 2 and later (running iOS 6 and later)


Probability is calculated as an overall chance to pull 1 or more copies of a unit for the attempted number of pulls using the Binomial distribution; remember that each pull is an independent event and past failures do not increase the likelihood of successful pulls in the future.
| Probability | to pull 1 or more | at rate(s) |
|---|
| Probability | to pull 1 or more | at rate(s) |
|---|---|---|
| 0% | Any Banner 5★ | |
| 0% | Any 5★ |


Welcome to Ski Host!
Our purpose: to help the vacation skier/snowboarder to have the local experience.
Register below to become a Ski Host!
Our purpose: to help the vacation skier/snowboarder to have the local experience.
Register below to become a Ski Host!


Top Ten English Songs With Lyrics
1. The Monster Eminem FT Rihanna Next
[Hook: Rihanna]
I'm friends with the monster that's under my bed
Get along with the voices inside of my head
You're trying to save me, stop holdin' your breath
And you think I'm crazy, yeah, you think I'm crazy
[Verse 1: Eminem]
I wanted the fame, but not the cover of Newsweek
Oh well, guess beggars can't be choosey
Wanted to receive attention for my music
Wanted to be left alone in public excuse me
For wanting my cake, and eat it too, and wanting it both ways
Fame made me a balloon cause my ego inflated when I blew, see
But it was confusing, cause all I wanted to do's be
The Bruce Lee of loose leaf
Abused ink, used it as a tool when blew steam
Hit the lottery, ooh-wee
But with what I gave up to get it was bittersweet
It was like winning a used mink
Ironic cause I think I'm getting so huge I need a shrink
I'm beginning to lose sleep
One sheep, two sheep
Going coo-coo and kooky as Kool Keith
But I'm actually weirder than you think
Cause I'm...
[Bridge: Rihanna] X2
Well, that's nothing
[Verse 2: Eminem]
Now, I ain't much of a poet but I know somebody once told me to seize the moment and don't squander it
Cause you never know when it all could be over tomorrow, so I keep conjuring
Sometimes I wonder where these thoughts spawn from
(Yeah, pondering'll do you wonders
No wonder you're losing your mind, the way it wanders)
Yodel-odel-ay-hee-hoo!
I think it went wandering off down yonder
And stumbled onto Jeff VanVonderen
Cause I need an interventionist to intervene between me and this monster
And save me from myself and all this conflict
Cause the very thing that I love's killing me and I can't conquer it
My OCD is conking me in the head, keep knockin'
Nobody's home, I'm sleepwalkin'
I'm just relaying what the voice in my head is saying
Don't shoot the messenger, I'm just friends with the...

Back 2.  One More Night By Maroon 5 Next
You and I go hard at each other like we're going to war.
You and I go rough, we keep throwing things and slamming the door.

You and I get sick, yeah, I know that we can't do this no more.

Try to tell you "stop", but your lipstick got me so out of breath.
I'll be waking up in the morning, probably hating myself.
And I'll be waking up, feeling satisfied but guilty as hell.

(Making me love you)
Yeah, I stopped using my head, using my head, let it all go.

Yeah, I stopped using my head, using my head, let it all go.

Back 4. Heart Attack By Enrique Iglesias Next
Loving you was easy,
Thought you'd never leave me
Yeah, yeah
Wrapped around my finger, see you when I see you
Yeah, yeah
Now.

 Drunk In Love Ft Jay-Z Beyonce Next
I've been drinking, I've been drinking
I get filthy when that liquor get into me
I've been thinking, I've been thinking
Why can't I keep my fingers off it, baby?

 Counting Stars By One Republic Next
Lately, I've been, I've been losing sleep
Dreaming about the things that we could be
But baby, I've been, I've been praying hard,
Said no more counting dollars
We'll be counting stars, yeah we'll be counting stars
I see this life like a swinging vine
Swing my heart across the line
In my face is flashing signs
Seek it out and ye shall find
Old, but I'm not that old
Young, but I'm not that bold
I don't think the world is sold
I'm just doing what we're told
I feel something so right
Doing the wrong thing
I feel something so wrong
Doing the right thing
I could lie, could lie, could lie
Everything that kills me makes me feel alive
Lately, I've been, I've been losing sleep
Dreaming about the things that we could be
But baby, I've been, I've been praying hard,
Said no more counting dollars
We'll be counting stars
Lately, I've been, I've been losing sleep
Dreaming about the things that we could be
But baby, I've been, I've been praying hard,
Said no more counting dollars
We'll be, we'll be counting stars
I feel your love and I feel it burn
Down this river, every turn
Hope is a four-letter word
Make that money, watch it burn
Old, but I'm not that old
Young, but I'm not that bold
I don't think the world is sold
I'm just doing what we're told
I feel something so wrong
Doing the right thing
I could lie, could lie, could lie
Everything that downs me, makes me wanna fly
Lately, I've been, I've been losing sleep
Dreaming about the things that we could be
But baby, I've been, I've been praying hard,
Said no more counting dollars
We'll be counting stars
Lately, I've been, I've been losing sleep
Dreaming about the things that we could be
But baby, I've been, I've been praying hard,
Said no more counting dollars
We'll be, we'll be counting stars
Take that money
Watch it burn
Sink in the river
The lessons I learned
Take that money
Watch it burn
Sink in the river
The lessons I learned
Take that money
Watch it burn
Sink in the river
The lessons I learned
Take that money
Watch it burn
Sink in the river
The lessons I learned
Everything that kills me... makes me feel alive
Lately, I've been, I've been losing sleep
Dreaming about the things that we could be
But baby, I've been, I've been praying hard,
Said no more counting dollars
We'll be counting stars
Lately, I've been, I've been losing sleep
Dreaming about the things that we could be
But baby, I've been, I've been praying hard,
Said no more counting dollars
We'll be, we'll be, counting stars
Take that money
Watch it burn
Sink in the river
The lessons I learned
Back 10.


{% extends "blog/base.html" %} {% load crispy_forms_tags %} {% block title %}
“The enemy are only 50 yards from us. We are heavily outnumbered. We are under devastating fire. I shall not withdraw an inch but will fight to our last man and our last round.”
-Major Somnath Sharma


Parse Cookie
header and populate
req.cookies
with an object keyed by the cookie names.
Optionally you may enable signed cookie support by passing a
secret
string, which assigns req.secret
so it
may be used by other middleware.
Create a new cookie parser middleware function using the given
secret
and options
.
secret
a string or array used for signing cookies. This is
optional and if not specified, will not parse signed cookies. If a
string is provided, this is used as the secret. If an array is provided,
an attempt will be made to unsign the cookie with each secret in order.
options
an object that is passed to
cookie.parse
as the second option. See
cookie for more
information.
decode
a function to decode the value of the cookie
The middleware will parse the Cookie
header on the request
and expose the cookie data as the property req.cookies
and,
if a secret
was provided, as the property
req.signedCookies
. These properties are name value pairs of
the cookie name to cookie value.
When secret
is provided, this module will unsign and validate
any signed cookie values and move those name value pairs from
req.cookies
into req.signedCookies
. A signed
cookie is a cookie that has a value prefixed with s:
. Signed
cookies that fail signature validation will have the value
false
instead of the tampered value.
In addition, this module supports special “JSON cookies”. These are cookie
where the value is prefixed with j:
. When these values are
encountered, the value will be exposed as the result of
JSON.parse
. If parsing fails, the original value will remain.
Parse a cookie value as a JSON cookie. This will return the parsed JSON value if it was a JSON cookie, otherwise, it will return the passed value.
Given an object, this will iterate over the keys and call
JSONCookie
on each value, replacing the original value with
the parsed value. This returns the same object that was passed in.
Parse a cookie value as a signed cookie. This will return the parsed
unsigned value if it was a signed cookie and the signature was valid. If
the value was not signed, the original value is returned. If the value was
signed but the signature could not be validated, false
is
returned.
The secret
argument can be an array or string. If a string is
provided, this is used as the secret. If an array is provided, an attempt
will be made to unsign the cookie with each secret in order.
Given an object, this will iterate over the keys and check if any value is a signed cookie. If it is a signed cookie and the signature is valid, the key will be deleted from the object and added to the new object that is returned.
The secret
argument can be an array or string. If a string is
provided, this is used as the secret. If an array is provided, an attempt
will be made to unsign the cookie with each secret in order.
var express = require('express')
var cookieParser = require('cookie-parser')
var app = express()
app.use(cookieParser())
app.get('/', function (req, res) {
// Cookies that have not been signed
console.log('Cookies: ', req.cookies)
// Cookies that have been signed
console.log('Signed Cookies: ', req.signedCookies)
})
app.listen(8080)
// curl command that sends an HTTP request with two cookies
// curl http://<IP_ADDRESS>:8080 --cookie "Cho=Kim;Greet=Hello"


Rails 5.1.0.rc1 (March 20, 2017)
- No changes.
Rails 5.1.0.beta1 (February 23, 2017)
Add
:args
toprocess.action_mailer
event.Yuji Yaginuma
Add parameterized invocation of mailers as a way to share before filters and defaults between actions. See ::ActionMailer::Parameterized for a full example of the benefit.
DHH
Allow lambdas to be used as lazy defaults in addition to procs.
DHH
Mime type: allow to custom content type when setting body in headers and attachments.
Example:
def test_emails ["invoice.pdf"] = "This is test File content" mail(body: "Hello there", content_type: "text/html") end
Minh Quy
Exception handling: use
rescue_from
to handle exceptions raised by mailer actions, by message delivery, and by deferred delivery jobs.Jeremy Daer
Please check 5-0-stable for previous changes.


Before you read this section, please make sure you are aware of that we have prepared some datasets for you in below packages. browseVignettes
is a function.
| package | installation | help | browseVignettes |
|---|---|---|---|
| RTCGA.rnaseq | biocLite('RTCGA.rnaseq') |
?rnaseq |
'RTCGA.rnaseq' |
| RTCGA.clinical | biocLite('RTCGA.clinical') |
?clinical |
'RTCGA.clinical' |
| RTCGA.mutations | biocLite('RTCGA.mutations') |
?mutations |
'RTCGA.mutations' |
| RTCGA.mRNA | biocLite('RTCGA.mRNA') |
?mRNA |
'RTCGA.mRNA' |
| RTCGA.miRNASeq | biocLite('RTCGA.miRNASeq') |
?miRNASeq |
'RTCGA.miRNASeq' |
| RTCGA.PANCAN12 | biocLite('RTCGA.PANCAN12') |
?pancan12 |
'RTCGA.PANCAN12' |
| RTCGA.RPPA | biocLite('RTCGA.RPPA') |
?RPPA |
'RTCGA.RPPA' |
| RTCGA.CNV | biocLite('RTCGA.CNV') |
?CNV |
'RTCGA.CNV' |
| RTCGA.methylation | biocLite('RTCGA.methylation') |
?methylation |
'RTCGA.methylation' |
The Cancer Genome Atlas provides data via Broad GDAC Firehose
. The number of cases in the most popular datasets can be checked with the following code that is based on the Broad GDAC Firehose
.
| Cohort | BCR | Clinical | Methylation | mRNASeq | |
|---|---|---|---|---|---|
| ACC-counts | ACC | 92 | 92 | 80 | 79 |
| BLCA-counts | BLCA | 412 | 412 | 412 | 408 |
| BRCA-counts | BRCA | 1098 | 1097 | 1097 | 1093 |
| CESC-counts | CESC | 307 | 307 | 307 | 304 |
| CHOL-counts | CHOL | 51 | 45 | 36 | 36 |
| COAD-counts | COAD | 460 | 458 | 457 | 457 |
Furthermore infoTCGA()
enables to extract possible cohorts names from TCGA Study.
Cohorts’ names stand for abbreviations of real names of cancer types.
The Cancer Genome Atlas provides datasets in many dates of release. You can check them with the following command.
The Cancer Genome Atlas provides various datasets for different cohort types. For example you can check all names of datasets provided for BRCA
with (second dimension stand for dataset size).
This lists only .zip
files.
If you know which cohort type you are interested in and which dataset name you are looking for and which release date suits you, you can download a dataset provided by TCGA Study with the following command.
You can specify cancerTypes
as a vector of characters if you would like to download the same dataset type for many cohorts.
Moreover you can just specify an abbreviation ora fragment of dataset name.
You can also specify date
argument if you would like to download datasets from previous (not the newest) releases.
All downloaded datasets are untarred and their .tar
files are deleted after untarring. You can also change this behaviour with untarFile
and removeTar
arguments. Sometimes more than one dataset fits the character provieded in dataSet
argument, then the first without FPPP
string is downloaded if possible. If you are interested in all datasets then you can change allDataSets
(by default FALSE
) parameter to TRUE
.
For specific datasets it is possible to read downloaded file into the tidy format. Fore more information check
Tweet


Last Work Day Updated Tasks
Last Work Day Updated Stories
Last Work Day Updated Defects
Today Updated Tasks
Today Updated Stories
Today Updated Defects


What is this project about?
Pair-programming can be unnecessary confusing, without a good editor.
Its difficult to keep an overview when your not sitting at the keyboard.
When hitting pageup/down the observer quickly looses his bearings.
What is needed is animation, scrolling, folding and assistence with refactoring.
Please take your time, and write a message in my guestbook,
>> click here.

Implementation plan
- use FreeBSD license.
- write backend in Ruby to obtain flexibility and robustness.
- write widget-frontends in C++ to obtain speed.
Experimental goals
- experiments with animated operations. Will this
reduce the observers confusion?
- dual-screen experiments. How does it work out if one is
writing code and the other one is writing comments?
What if you can hand over the keyboard to the observer, just
by pressing F12, so that you become the observer?
- improve user experience.. HCI + contextual design.
$Date: 2004/11/03 23:03:19 $


--- layout: pattern title: Block List summary: Blocky lists of content. Typically useful for secondary type navigation. ---


Making a Useful Tool Creates
It's Own Opportunities
The goal was to create a website that becomes a useful tool to sales reps and accounts. Making the right beer easier to find will promote sales and increase traffic leading to other marketing opportunities. The site needs to reflect the companies history and expertise while looking forward and relevant to the market today.
Goals and Personas Are a Framework for Decision Making
To establish a framework to guide the process goals were stated, personas created and a survey made. After the primary inquiry the initial site architecture and wireframing was done. Secondary feedback from the sales staff lead to insights that local and new beers were the most prominent categories accounts were searching for.
Like a Branching River Many Paths Lead to the Same Source
The path to finding the right product for the account can take different approaches. Searching by brewery or style, segment or location, or just casually browsing the latest beers. The search functionality was aided with a faceted filter allowing the user to drill down by style, season, package or abv.
On the product details page all the pieces come together. All the relevant info for the beer is here, including an image carrousel, package formats and item numbers, featured ingredients, months available and ratings from Untappd and RateBeer that trigger above a certain threshold.
On the product details page all the pieces come together. All the relevant info for the beer is here, including an image carrousel, package formats and item numbers, featured ingredients, months available and ratings from Untappd and RateBeer that trigger above a certain threshold.
Telling a New Story for a Company With History
Louis Glunz Beer Inc. has been in business since 1888 and has been a part of and grown with the beer scene in Chicago ever since. Developing the branding for the site looks to include nods to the past, but must look relevant to contemporary audiences. The previous branding only amounted to a logo. So theme, color and typography had to be established.
The strong linear drafted look is echoed by the cards styling for discrete information packets. The colors scheme are meant to evoke the colors of beer as well as tipping the hat to an earlier time. Incorporating these into gradients allows me to use a design trend and further evoke the appearance of a light or dark beer in a glass.
Let CSS Cascade & SASS Extend
I used the products details page, beer post archive pages, and a style guide to construct my default styling and create reusable CSS classes. After having this code rock solid, using cascading styles and the extend feature of SASS let me put together all the supporting pages and content quickly and uniformly.
42k Users
32.4%
60k Sessions
36.7%
In the year and a half since the new site has been launched there has been a 32% increase in users and a 37% increase in sessions. As well a more prominent contact form leads to contacts from new accounts and beer drinkers. The site has also lead to increased visibility for smaller brands. People contact us all over the world looking asking where these brands can be purchased.


Previous Non-Opiate Experiences: Dextro-amphetamine, Amphetamine, Methylphenidate, 5-MEO-DiPT, Mushrooms, Marijuana, DXM, Various Benzodiazepines and GBL.
Opiates Experienced: Demerol (Meperidine), Codeine, Hydrocodone, Oxycodone, Morphine and Ultram (Tramadol).
Due to certain medical conditions I have had the opportunity to sample different opiates of the medical world for pleasure and for pain. I have always enjoyed the feeling of opiates but at the same time I’ve had to watch myself in order to keep tolerance, dependence and addiction at bay. While I have had fun with all the opiates on the list I have found that after the initial use their duration became shorter and that they also began offering a strange “come down” effect. I have tried abstaining from opiates to see if it was a tolerance issue but the comedown was still there. After the bliss of an hour or 2, I would begin to feel exceedingly irritable. This is about when my interest in these substances waned, and my interest in Tramadol began to grow.
Tramadol is a synthetic analgesic who’s mode of action is not completely understood. It has been shown to exhibit some of the same effects as other opiate pain medications but there is no consensus in either the medical or the recreational community whether it is a true opiate/opioid. As of now it is not scheduled in America and is relatively easy to get prescribed. I routinely get 50 count bottles of Ultram with 3 refills and no complaints from my doctor; where as getting hydrocodone for my chronic pain can be met with cries of “Criminal” and medical gauntlet running.
Back to the story though. I was prescribed Tramadol for my day time pain at a dosage of 100-200 mg a day. When I first took it I was on a relatively high amount of hydrocodone for a relatively high amount of pain and was not expecting to be impressed by this previously unheard of drug. Amazingly the effects were incredible and over time I stopped taking all other pain medication.
“The Joys of Tramadol”
1. It lasts from 3-9 hours
2. Little constipation
3. It does not disrupt or muddle thinking
4. Apparently little tolerance. I have taken the same 100mg dose once ever 2-3 days for over a year now and have never had effects any weaker than the first time.
5. Less “come down” than other opiates.
Here is a summery of a fairly standard experience with Tramadol.
T+ 0:00
I am in a stable mind set with the usual annoying pain, but typically normal. I swallow 2 Tramadol with a little food to pad the stomach (best not to risk any nausea).
T+ 0:30
I began my exercises and weight lifting. Nothing at all can be felt out of the ordinary.

T+ 1:00
Body pain starts to fade a bit as I finish my workout and drink some water.
T+ 1:15
It hits me when I step into the shower. It’s not like many opiate medications that can have the tendency to overwhelm you (albeit in a good way) in the onset, the beginning of the experience of Tramadol is like a breath of fresh air. Suddenly I am calmed and my mood is elevated. Unlike many other drugs than can provide euphoria that can seem forced or chemical, the euphoria from Tramadol seems like the most natural thing in the world. It just feels completely right, I can easily forget that I have taken a drug at all.
It is difficult to describe the experience itself, its nothing like “the full body orgasm” that some heroin users describe. It’s more like a “full body blanket”, it’s as if the most comfortable, softest, pink blanket is being wrapped around me in both a physical and emotional way. It is like laying back and talking with my best friend. It’s like walking outside on the first day of summer and smelling the fresh cut grass. My problems have not disappeared, I have not escaped them, but the little annoyances of life have had the volume turned down a notch. Tramadol has often giving me the opportunity to reflect and feel optimistic about the future.
I’ll admit that it all sounds a little intense. Most likely because I am focusing on it so intently. The great thing about Tramadol, however, is that it does not inhibit my activities at all.  It just feels natural to continue to do, whatever it is that I do. Doing work is fine, conversations are great, sports are fun, there are hardly any activities that I can think of that Tramadol detracts from. Well except sleep. It’s no good for sleeping.
This drug is a great at multitasking. I can lounge around and watch movies or I can go out and give an academic presentation. It doesn’t matter, It just feels natural.
T+ 2:00
Still operating at the same level of enjoyment. It falls into the background of whatever I am doing more while still giving everything around me a slight glow (emotional not visual).
T+ 3:00
The effects have dropped slightly but I am still having a great time.
T+ 4:00
The effects are at about 1/3 of their strongest (peak around +2:00).
T+ 5:00-8:00
The effects slowly drop off until there is just a tiny but pleasant calming buzz in the back of my head. I usually remain emotionally lifted until I go to sleep that night.
Reflection: If there is such a thing as a “perfect drug” this is as close as I have found. It doesn’t overwhelm, it simply enhances. It provides a very natural feeling of tranquility and calm. Now I can’t make this entirely a positive report. Opiates can be very addictive to those without strong self control. Tramadol while not be considered a “true opiate” is addictive and will cause withdrawal symptoms I am told, when taking frequently and in large amounts. Personally I take 100mg of Tramadol (half of the actual recommended daily dose) every 2 or 3 days. The effects are always the same and I have felt no withdrawal on the off days.
*Note: Many people to not receive the same effects that I do from this drug. There are some for whom it is useless, or that receive only a minimum effect. But there are others, like me, who are lucky enough to enjoy this drug in its surprising glory.
PS: It’s not very safe to mix pain medications and alcohol
Have fun, be safe.
Experience Reports are the writings and opinions of the individual authors who submit them.
Some of the activities described are dangerous and/or illegal and none are recommended by Erowid.


September-December 2017
For students who need help budgeting their money, Budge is a spend management website that provides a simple set of budgeting tools, including a friendly chatbot to help users better manage their money. Unlike other spend management solutions like Mint, Budge is friendly and customized for college students and their needs.
Budge is a project I created in my Interaction Design class in the Fall of 2018
I conducted a lot of user interviews on campus. My target audience was college students. I found that students were really interested in learning how to budget, managing their finances, and investing in the stock market. Their main motives were being able to better manage the money they made while working, spending less money on food, and being prepared for life after college. Currently, most students are not budgeting or using apps like Bank of America or Mint. Some are even doing the math in their heads. Many complain that the apps are not customized and that budgeting is scary.
Using my research, I created personas. These personas reflected the interviews I conducted at my university.
I also did several iterations of a logo for my website. A lot of my initial sketches were very generic and also not very expressive of the brand I was trying to create. I decided on using two overlapping B's in the Akzidenz Grotesk typeface. I also decided on the specific shade of green based on different financial companies I had researched.
Based on my research, I realized I wanted to make a customizable website for college students to better budget their money. I wanted to incorporate relevant categories for college students, like Venmo. I also wanted it to be a private website, not intended for social use. Also, this would be an ad-free website, as many students complained about ads. I focused primarily on two workflows.
1. Creating a Budget: For this workflow, there is a create budget page where they can input how much they spend in various different sectors. Once this is complete, the user recieves a set of bars with budgets per month. I made sure to include venmo as a category so the college student would get better use out of this application. Once the budget is created and the user is active, the budget will appear as a pie chart on their home page.
2. A Friendly Chatbot: I also wanted to create a workflow for someone who needed more help creating a budget. For this persona, I decided to have a friendly chatbot with which the user could interact with. This workflow walks the user through a series of questions that creates a budget template based on their answers.
Both of these workflows are represented in videos at the bottom of this page!
The first round of digital prototyping I did was using Balsamiq. Here is an example of three of the screens the user would see throughout their workflow.
The second round of prototyping I did was using Adobe XD.
I prototyped the final web application using Adobe XD. This specific classed focused more on web design, so I have a more fleshed out prototype for the desktop view. I also have a mobile view that is less functional!


Congress Says SC's Ayodhya Verdict Has Closed Doors For BJP, Others To Politicise It
Congress Working Committee “appealed to all parties concerned and all communities to abide by the secular values" enshrined in Constitution.
by NewsroomReacting to the Supreme Court verdict on Saturday, Congress said it respects the judgment and is in favour of Ram temple construction.
The top court granted the disputed site to the Hindu parties and ordered that the Muslim litigants be given a five-acre alternative site to construct a mosque.
Congress leader Randeep Singh Surjewala said that the judgment “has not only opened the doors for the temple’s construction, but also closed the doors of the BJP and others to politicise it.”
In a statement, the Congress Working Committee “appealed to all parties concerned and all communities to abide by the secular values and spirit of fraternity enshrined in the Constitution and to maintain peace and harmony.”
“It is the responsibility of each one of us to reaffirm our tradition of mutual respect and unity among all that has defined our society through the ages,” it added.
Congress general secretary Priyanka Gandhi Vadra said all parties should respect the Supreme Court verdict on Ayodhya issue and maintain India’s age-old tradition of living together in harmony and brotherhood.
(With PTI inputs)


--- description: 'A page where a logged in customer can read/edit their customer info.' action: 'shop:customerProfile' template: main protocol: all published: true name: Account url: /account --- {{ partial('partial-banner-alt', { banner: { title: 'Account' }}) }}


누구에게나 잘 대해준다.
시간을 잘 지키면서 상대방을 배려한다.
친구들과 싸우지 않고 잘 지낸다.
Those days of more fun than now
My job is to do it on my own.
Days full of homework
The beginning of a unfamiliar experience
Movie is what keeps me going.
I especially watch a sad movie. Images from the movie still lingers in my mind.
It is always fun.
Shopping with friends is always fun. But it costs so much money that I have to work.
An indispensable part of my life
going a good restaurant is the ultimate reason why I earn money.