mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-10-01 02:35:48 -04:00
adding pegmarkdown support library.
git-svn-id: http://svn.code.sf.net/p/retroshare/code/branches/v0.5-gxs-b1@5953 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
parent
4413536926
commit
3be22536df
@ -2,6 +2,7 @@
|
||||
#include <algorithm>
|
||||
#include <math.h>
|
||||
#include <sstream>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "p3posted.h"
|
||||
#include "gxs/rsgxsflags.h"
|
||||
|
208
supportlibs/pegmarkdown/GLibFacade.c
Normal file
208
supportlibs/pegmarkdown/GLibFacade.c
Normal file
@ -0,0 +1,208 @@
|
||||
/*
|
||||
* GLibFacade.c
|
||||
* MultiMarkdown
|
||||
*
|
||||
* Created by Daniel Jalkut on 7/26/11.
|
||||
* Modified by Fletcher T. Penney on 9/15/11.
|
||||
* Modified by Dan Lowe on 1/3/12.
|
||||
* Copyright 2011 __MyCompanyName__. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "GLibFacade.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/*
|
||||
* The following section came from:
|
||||
*
|
||||
* http://lists-archives.org/mingw-users/12649-asprintf-missing-vsnprintf-
|
||||
* behaving-differently-and-_vsncprintf-undefined.html
|
||||
*
|
||||
* and
|
||||
*
|
||||
* http://groups.google.com/group/jansson-users/browse_thread/thread/
|
||||
* 76a88d63d9519978/041a7d0570de2d48?lnk=raot
|
||||
*/
|
||||
|
||||
/* Solaris and Windows do not provide vasprintf() or asprintf(). */
|
||||
#if defined(__WIN32) || (defined(__SVR4) && defined(__sun))
|
||||
int vasprintf( char **sptr, char *fmt, va_list argv )
|
||||
{
|
||||
int wanted = vsnprintf( *sptr = NULL, 0, fmt, argv );
|
||||
if( (wanted > 0) && ((*sptr = malloc( 1 + wanted )) != NULL) )
|
||||
return vsprintf( *sptr, fmt, argv );
|
||||
|
||||
return wanted;
|
||||
}
|
||||
|
||||
int asprintf( char **sptr, char *fmt, ... )
|
||||
{
|
||||
int retval;
|
||||
va_list argv;
|
||||
va_start( argv, fmt );
|
||||
retval = vasprintf( sptr, fmt, argv );
|
||||
va_end( argv );
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* GString */
|
||||
|
||||
#define kStringBufferStartingSize 1024
|
||||
#define kStringBufferGrowthMultiplier 2
|
||||
|
||||
GString* g_string_new(char *startingString)
|
||||
{
|
||||
GString* newString = malloc(sizeof(GString));
|
||||
|
||||
if (startingString == NULL) startingString = "";
|
||||
|
||||
size_t startingBufferSize = kStringBufferStartingSize;
|
||||
size_t startingStringSize = strlen(startingString);
|
||||
while (startingBufferSize < (startingStringSize + 1))
|
||||
{
|
||||
startingBufferSize *= kStringBufferGrowthMultiplier;
|
||||
}
|
||||
|
||||
newString->str = malloc(startingBufferSize);
|
||||
newString->currentStringBufferSize = startingBufferSize;
|
||||
strncpy(newString->str, startingString, startingStringSize);
|
||||
newString->str[startingStringSize] = '\0';
|
||||
newString->currentStringLength = startingStringSize;
|
||||
|
||||
return newString;
|
||||
}
|
||||
|
||||
char* g_string_free(GString* ripString, bool freeCharacterData)
|
||||
{
|
||||
char* returnedString = ripString->str;
|
||||
if (freeCharacterData)
|
||||
{
|
||||
if (ripString->str != NULL)
|
||||
{
|
||||
free(ripString->str);
|
||||
}
|
||||
returnedString = NULL;
|
||||
}
|
||||
|
||||
free(ripString);
|
||||
|
||||
return returnedString;
|
||||
}
|
||||
|
||||
static void ensureStringBufferCanHold(GString* baseString, size_t newStringSize)
|
||||
{
|
||||
size_t newBufferSizeNeeded = newStringSize + 1;
|
||||
if (newBufferSizeNeeded > baseString->currentStringBufferSize)
|
||||
{
|
||||
size_t newBufferSize = baseString->currentStringBufferSize;
|
||||
|
||||
while (newBufferSizeNeeded > newBufferSize)
|
||||
{
|
||||
newBufferSize *= kStringBufferGrowthMultiplier;
|
||||
}
|
||||
|
||||
baseString->str = realloc(baseString->str, newBufferSize);
|
||||
baseString->currentStringBufferSize = newBufferSize;
|
||||
}
|
||||
}
|
||||
|
||||
void g_string_append(GString* baseString, char* appendedString)
|
||||
{
|
||||
if ((appendedString != NULL) && (strlen(appendedString) > 0))
|
||||
{
|
||||
size_t appendedStringLength = strlen(appendedString);
|
||||
size_t newStringLength = baseString->currentStringLength + appendedStringLength;
|
||||
ensureStringBufferCanHold(baseString, newStringLength);
|
||||
|
||||
/* We already know where the current string ends, so pass that as the starting address for strncat */
|
||||
strncat(baseString->str + baseString->currentStringLength, appendedString, appendedStringLength);
|
||||
baseString->currentStringLength = newStringLength;
|
||||
}
|
||||
}
|
||||
|
||||
void g_string_append_c(GString* baseString, char appendedCharacter)
|
||||
{
|
||||
size_t newSizeNeeded = baseString->currentStringLength + 1;
|
||||
ensureStringBufferCanHold(baseString, newSizeNeeded);
|
||||
|
||||
baseString->str[baseString->currentStringLength] = appendedCharacter;
|
||||
baseString->currentStringLength++;
|
||||
baseString->str[baseString->currentStringLength] = '\0';
|
||||
}
|
||||
|
||||
void g_string_append_printf(GString* baseString, char* format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
char* formattedString = NULL;
|
||||
vasprintf(&formattedString, format, args);
|
||||
if (formattedString != NULL)
|
||||
{
|
||||
g_string_append(baseString, formattedString);
|
||||
free(formattedString);
|
||||
}
|
||||
}
|
||||
|
||||
void g_string_prepend(GString* baseString, char* prependedString)
|
||||
{
|
||||
if ((prependedString != NULL) && (strlen(prependedString) > 0))
|
||||
{
|
||||
size_t prependedStringLength = strlen(prependedString);
|
||||
size_t newStringLength = baseString->currentStringLength + prependedStringLength;
|
||||
ensureStringBufferCanHold(baseString, newStringLength);
|
||||
|
||||
memmove(baseString->str + prependedStringLength, baseString->str, baseString->currentStringLength);
|
||||
strncpy(baseString->str, prependedString, prependedStringLength);
|
||||
baseString->currentStringLength = newStringLength;
|
||||
baseString->str[baseString->currentStringLength] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* GSList */
|
||||
|
||||
void g_slist_free(GSList* ripList)
|
||||
{
|
||||
GSList* thisListItem = ripList;
|
||||
while (thisListItem != NULL)
|
||||
{
|
||||
GSList* nextItem = thisListItem->next;
|
||||
|
||||
/* I guess we don't release the data? Non-retained memory management is hard... let's figure it out later. */
|
||||
free(thisListItem);
|
||||
|
||||
thisListItem = nextItem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Currently only used for markdown_output.c endnotes printing */
|
||||
GSList* g_slist_reverse(GSList* theList)
|
||||
{
|
||||
GSList* lastNodeSeen = NULL;
|
||||
|
||||
/* Iterate the list items, tacking them on to our new reversed List as we find them */
|
||||
GSList* listWalker = theList;
|
||||
while (listWalker != NULL)
|
||||
{
|
||||
GSList* nextNode = listWalker->next;
|
||||
listWalker->next = lastNodeSeen;
|
||||
lastNodeSeen = listWalker;
|
||||
listWalker = nextNode;
|
||||
}
|
||||
|
||||
return lastNodeSeen;
|
||||
}
|
||||
|
||||
GSList* g_slist_prepend(GSList* targetElement, void* newElementData)
|
||||
{
|
||||
GSList* newElement = malloc(sizeof(GSList));
|
||||
newElement->data = newElementData;
|
||||
newElement->next = targetElement;
|
||||
return newElement;
|
||||
}
|
||||
|
67
supportlibs/pegmarkdown/GLibFacade.h
Normal file
67
supportlibs/pegmarkdown/GLibFacade.h
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* GLibFacade.h
|
||||
* MultiMarkdown
|
||||
*
|
||||
* Created by Daniel Jalkut on 7/26/11.
|
||||
* Copyright 2011 __MyCompanyName__. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __MARKDOWN_GLIB_FACADE__
|
||||
#define __MARKDOWN_GLIB_FACADE__
|
||||
|
||||
/* peg_markdown uses the link symbol for its own purposes */
|
||||
#define link MARKDOWN_LINK_IGNORED
|
||||
#include <unistd.h>
|
||||
#undef link
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <ctype.h>
|
||||
|
||||
typedef int gboolean;
|
||||
typedef char gchar;
|
||||
|
||||
/* This style of bool is used in shared source code */
|
||||
#define FALSE false
|
||||
#define TRUE true
|
||||
|
||||
/* WE implement minimal mirror implementations of GLib's GString and GSList
|
||||
* sufficient to cover the functionality required by MultiMarkdown.
|
||||
*
|
||||
* NOTE: THese are 100% clean, from-scratch implementations using only the
|
||||
* GLib function prototype as guide for behavior.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* Current UTF8 byte stream this string represents */
|
||||
char* str;
|
||||
|
||||
/* Where in the str buffer will we add new characters */
|
||||
/* or append new strings? */
|
||||
int currentStringBufferSize;
|
||||
int currentStringLength;
|
||||
} GString;
|
||||
|
||||
GString* g_string_new(char *startingString);
|
||||
char* g_string_free(GString* ripString, bool freeCharacterData);
|
||||
|
||||
void g_string_append_c(GString* baseString, char appendedCharacter);
|
||||
void g_string_append(GString* baseString, char *appendedString);
|
||||
|
||||
void g_string_prepend(GString* baseString, char* prependedString);
|
||||
|
||||
void g_string_append_printf(GString* baseString, char* format, ...);
|
||||
|
||||
/* Just implement a very simple singly linked list. */
|
||||
|
||||
typedef struct _GSList
|
||||
{
|
||||
void* data;
|
||||
struct _GSList* next;
|
||||
} GSList;
|
||||
|
||||
void g_slist_free(GSList* ripList);
|
||||
GSList* g_slist_prepend(GSList* targetElement, void* newElementData);
|
||||
GSList* g_slist_reverse(GSList* theList);
|
||||
|
||||
#endif
|
88
supportlibs/pegmarkdown/LICENSE
Normal file
88
supportlibs/pegmarkdown/LICENSE
Normal file
@ -0,0 +1,88 @@
|
||||
markdown in c, implemented using PEG grammar
|
||||
Copyright (c) 2008-2011 John MacFarlane
|
||||
ODF output code (c) 2011 Fletcher T. Penney
|
||||
|
||||
peg-markdown is released under both the GPL and MIT licenses.
|
||||
You may pick the license that best fits your needs.
|
||||
|
||||
The GPL
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
The MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
|
||||
peg-0.1.4 (included for convenience - http://piumarta.com/software/peg/)
|
||||
|
||||
Copyright (c) 2007 by Ian Piumarta
|
||||
All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the 'Software'),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, provided that the above copyright notice(s) and this
|
||||
permission notice appear in all copies of the Software. Acknowledgement
|
||||
of the use of this Software in supporting documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK.
|
||||
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
|
||||
my_getopt (included for convenience - http://www.geocities.com/bsittler/)
|
||||
|
||||
Copyright 1997, 2000, 2001, 2002, 2006, Benjamin Sittler
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
42
supportlibs/pegmarkdown/Makefile.orig
Normal file
42
supportlibs/pegmarkdown/Makefile.orig
Normal file
@ -0,0 +1,42 @@
|
||||
uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
|
||||
ifneq (,$(findstring MINGW,$(uname_S)))
|
||||
X = .exe
|
||||
endif
|
||||
|
||||
export X
|
||||
|
||||
PROGRAM=markdown$(X)
|
||||
CFLAGS ?= -Wall -O3 -ansi -D_GNU_SOURCE # -flto for newer GCC versions
|
||||
OBJS=markdown_parser.o markdown_output.o markdown_lib.o utility_functions.o parsing_functions.o odf.o
|
||||
PEGDIR=peg-0.1.9
|
||||
LEG=$(PEGDIR)/leg$(X)
|
||||
PKG_CONFIG = pkg-config
|
||||
|
||||
ALL : $(PROGRAM)
|
||||
|
||||
$(LEG): $(PEGDIR)
|
||||
CC=gcc make -C $(PEGDIR)
|
||||
|
||||
%.o : %.c markdown_peg.h
|
||||
$(CC) -c `$(PKG_CONFIG) --cflags glib-2.0` $(CFLAGS) -o $@ $<
|
||||
|
||||
$(PROGRAM) : markdown.c $(OBJS)
|
||||
$(CC) `$(PKG_CONFIG) --cflags glib-2.0` $(CFLAGS) -o $@ $< $(OBJS) `$(PKG_CONFIG) --libs glib-2.0`
|
||||
|
||||
markdown_parser.c : markdown_parser.leg $(LEG) markdown_peg.h parsing_functions.c utility_functions.c
|
||||
$(LEG) -o $@ $<
|
||||
|
||||
.PHONY: clean test
|
||||
|
||||
clean:
|
||||
rm -f markdown_parser.c $(PROGRAM) $(OBJS)
|
||||
|
||||
distclean: clean
|
||||
make -C $(PEGDIR) clean
|
||||
\
|
||||
test: $(PROGRAM)
|
||||
cd MarkdownTest_1.0.3; \
|
||||
./MarkdownTest.pl --script=../$(PROGRAM) --tidy
|
||||
|
||||
leak-check: $(PROGRAM)
|
||||
valgrind --leak-check=full ./markdown README
|
176
supportlibs/pegmarkdown/MarkdownTest_1.0.3/MarkdownTest.pl
Executable file
176
supportlibs/pegmarkdown/MarkdownTest_1.0.3/MarkdownTest.pl
Executable file
@ -0,0 +1,176 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
#
|
||||
# MarkdownTester -- Run tests for Markdown implementations
|
||||
#
|
||||
# Copyright (c) 2004-2005 John Gruber
|
||||
# <http://daringfireball.net/projects/markdown/>
|
||||
#
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Getopt::Long;
|
||||
use Benchmark;
|
||||
|
||||
our $VERSION = '1.0.2';
|
||||
# Sat 24 Dec 2005
|
||||
|
||||
my $time_start = new Benchmark;
|
||||
my $test_dir = "Tests";
|
||||
my $script = "./Markdown.pl";
|
||||
my $use_tidy = 0;
|
||||
my ($flag_version);
|
||||
|
||||
GetOptions (
|
||||
"script=s" => \$script,
|
||||
"testdir=s" => \$test_dir,
|
||||
"tidy" => \$use_tidy,
|
||||
"version" => \$flag_version,
|
||||
);
|
||||
|
||||
if($flag_version) {
|
||||
my $progname = $0;
|
||||
$progname =~ s{.*/}{};
|
||||
die "$progname version $VERSION\n";
|
||||
}
|
||||
|
||||
unless (-d $test_dir) { die "'$test_dir' is not a directory.\n"; }
|
||||
unless (-f $script) { die "$script does not exist.\n"; }
|
||||
unless (-x $script) { die "$script is not executable.\n"; }
|
||||
|
||||
my $tests_passed = 0;
|
||||
my $tests_failed = 0;
|
||||
|
||||
TEST:
|
||||
foreach my $testfile (glob "$test_dir/*.text") {
|
||||
my $testname = $testfile;
|
||||
$testname =~ s{.*/(.+)\.text$}{$1}i;
|
||||
print "$testname ... ";
|
||||
|
||||
# Look for a corresponding .html file for each .text file:
|
||||
my $resultfile = $testfile;
|
||||
$resultfile =~ s{\.text$}{\.html}i;
|
||||
unless (-f $resultfile) {
|
||||
print "'$resultfile' does not exist.\n\n";
|
||||
next TEST;
|
||||
}
|
||||
|
||||
# open(TEST, $testfile) || die("Can't open testfile: $!");
|
||||
open(RESULT, $resultfile) || die("Can't open resultfile: $!");
|
||||
undef $/;
|
||||
# my $t_input = <TEST>;
|
||||
my $t_result = <RESULT>;
|
||||
|
||||
my $t_output = `'$script' '$testfile'`;
|
||||
|
||||
# Normalize the output and expected result strings:
|
||||
$t_result =~ s/\s+\z//; # trim trailing whitespace
|
||||
$t_output =~ s/\s+\z//; # trim trailing whitespace
|
||||
if ($use_tidy) {
|
||||
# Escape the strings, pass them through to CLI tidy tool for tag-level equivalency
|
||||
$t_result =~ s{'}{'\\''}g; # escape ' chars for shell
|
||||
$t_output =~ s{'}{'\\''}g;
|
||||
$t_result = `echo '$t_result' | tidy --show-body-only 1 --quiet 1 --show-warnings 0`;
|
||||
$t_output = `echo '$t_output' | tidy --show-body-only 1 --quiet 1 --show-warnings 0`;
|
||||
}
|
||||
|
||||
if ($t_output eq $t_result) {
|
||||
print "OK\n";
|
||||
$tests_passed++;
|
||||
}
|
||||
else {
|
||||
print "FAILED\n\n";
|
||||
# This part added by JM to print diffs
|
||||
open(OUT, '>tmp1') or die $!;
|
||||
print OUT $t_output or die $!;
|
||||
open(RES, '>tmp2') or die $!;
|
||||
print RES $t_result or die $!;
|
||||
print `diff tmp1 tmp2`;
|
||||
close RES;
|
||||
close OUT;
|
||||
print "\n";
|
||||
`rm tmp?`;
|
||||
# End of added part
|
||||
$tests_failed++;
|
||||
}
|
||||
}
|
||||
|
||||
print "\n\n";
|
||||
print "$tests_passed passed; $tests_failed failed.\n";
|
||||
|
||||
my $time_end = new Benchmark;
|
||||
my $time_diff = timediff($time_end, $time_start);
|
||||
print "Benchmark: ", timestr($time_diff), "\n";
|
||||
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
B<MarkdownTest>
|
||||
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<MarkdownTest.pl> [ B<--options> ] [ I<file> ... ]
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
Use "--" to end switch parsing. For example, to open a file named "-z", use:
|
||||
|
||||
MarkdownTest.pl -- -z
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<--script>
|
||||
|
||||
Specify the path to the Markdown script to test. Defaults to
|
||||
"./Markdown.pl". Example:
|
||||
|
||||
./MarkdownTest.pl --script ./PHP-Markdown/php-markdown
|
||||
|
||||
=item B<--testdir>
|
||||
|
||||
Specify the path to a directory containing test data. Defaults to "Tests".
|
||||
|
||||
=item B<--tidy>
|
||||
|
||||
Flag to turn on using the command line 'tidy' tool to normalize HTML
|
||||
output before comparing script output to the expected test result.
|
||||
Assumes that the 'tidy' command is available in your PATH. Defaults to
|
||||
off.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
|
||||
=head1 BUGS
|
||||
|
||||
|
||||
|
||||
=head1 VERSION HISTORY
|
||||
|
||||
1.0 Mon 13 Dec 2004-2005
|
||||
|
||||
1.0.1 Mon 19 Sep 2005
|
||||
|
||||
+ Better handling of case when foo.text exists, but foo.html doesn't.
|
||||
It now prints a message and moves on, rather than dying.
|
||||
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
Copyright (c) 2004-2005 John Gruber
|
||||
<http://daringfireball.net/>
|
||||
All rights reserved.
|
||||
|
||||
This is free software; you may redistribute it and/or modify it under
|
||||
the same terms as Perl itself.
|
||||
|
||||
=cut
|
@ -0,0 +1,17 @@
|
||||
<p>AT&T has an ampersand in their name.</p>
|
||||
|
||||
<p>AT&T is another way to write it.</p>
|
||||
|
||||
<p>This & that.</p>
|
||||
|
||||
<p>4 < 5.</p>
|
||||
|
||||
<p>6 > 5.</p>
|
||||
|
||||
<p>Here's a <a href="http://example.com/?foo=1&bar=2">link</a> with an ampersand in the URL.</p>
|
||||
|
||||
<p>Here's a link with an amersand in the link text: <a href="http://att.com/" title="AT&T">AT&T</a>.</p>
|
||||
|
||||
<p>Here's an inline <a href="/script?foo=1&bar=2">link</a>.</p>
|
||||
|
||||
<p>Here's an inline <a href="/script?foo=1&bar=2">link</a>.</p>
|
@ -0,0 +1,21 @@
|
||||
AT&T has an ampersand in their name.
|
||||
|
||||
AT&T is another way to write it.
|
||||
|
||||
This & that.
|
||||
|
||||
4 < 5.
|
||||
|
||||
6 > 5.
|
||||
|
||||
Here's a [link] [1] with an ampersand in the URL.
|
||||
|
||||
Here's a link with an amersand in the link text: [AT&T] [2].
|
||||
|
||||
Here's an inline [link](/script?foo=1&bar=2).
|
||||
|
||||
Here's an inline [link](</script?foo=1&bar=2>).
|
||||
|
||||
|
||||
[1]: http://example.com/?foo=1&bar=2
|
||||
[2]: http://att.com/ "AT&T"
|
@ -0,0 +1,18 @@
|
||||
<p>Link: <a href="http://example.com/">http://example.com/</a>.</p>
|
||||
|
||||
<p>With an ampersand: <a href="http://example.com/?foo=1&bar=2">http://example.com/?foo=1&bar=2</a></p>
|
||||
|
||||
<ul>
|
||||
<li>In a list?</li>
|
||||
<li><a href="http://example.com/">http://example.com/</a></li>
|
||||
<li>It should.</li>
|
||||
</ul>
|
||||
|
||||
<blockquote>
|
||||
<p>Blockquoted: <a href="http://example.com/">http://example.com/</a></p>
|
||||
</blockquote>
|
||||
|
||||
<p>Auto-links should not occur here: <code><http://example.com/></code></p>
|
||||
|
||||
<pre><code>or here: <http://example.com/>
|
||||
</code></pre>
|
@ -0,0 +1,13 @@
|
||||
Link: <http://example.com/>.
|
||||
|
||||
With an ampersand: <http://example.com/?foo=1&bar=2>
|
||||
|
||||
* In a list?
|
||||
* <http://example.com/>
|
||||
* It should.
|
||||
|
||||
> Blockquoted: <http://example.com/>
|
||||
|
||||
Auto-links should not occur here: `<http://example.com/>`
|
||||
|
||||
or here: <http://example.com/>
|
@ -0,0 +1,118 @@
|
||||
<p>These should all get escaped:</p>
|
||||
|
||||
<p>Backslash: \</p>
|
||||
|
||||
<p>Backtick: `</p>
|
||||
|
||||
<p>Asterisk: *</p>
|
||||
|
||||
<p>Underscore: _</p>
|
||||
|
||||
<p>Left brace: {</p>
|
||||
|
||||
<p>Right brace: }</p>
|
||||
|
||||
<p>Left bracket: [</p>
|
||||
|
||||
<p>Right bracket: ]</p>
|
||||
|
||||
<p>Left paren: (</p>
|
||||
|
||||
<p>Right paren: )</p>
|
||||
|
||||
<p>Greater-than: ></p>
|
||||
|
||||
<p>Hash: #</p>
|
||||
|
||||
<p>Period: .</p>
|
||||
|
||||
<p>Bang: !</p>
|
||||
|
||||
<p>Plus: +</p>
|
||||
|
||||
<p>Minus: -</p>
|
||||
|
||||
<p>These should not, because they occur within a code block:</p>
|
||||
|
||||
<pre><code>Backslash: \\
|
||||
|
||||
Backtick: \`
|
||||
|
||||
Asterisk: \*
|
||||
|
||||
Underscore: \_
|
||||
|
||||
Left brace: \{
|
||||
|
||||
Right brace: \}
|
||||
|
||||
Left bracket: \[
|
||||
|
||||
Right bracket: \]
|
||||
|
||||
Left paren: \(
|
||||
|
||||
Right paren: \)
|
||||
|
||||
Greater-than: \>
|
||||
|
||||
Hash: \#
|
||||
|
||||
Period: \.
|
||||
|
||||
Bang: \!
|
||||
|
||||
Plus: \+
|
||||
|
||||
Minus: \-
|
||||
</code></pre>
|
||||
|
||||
<p>Nor should these, which occur in code spans:</p>
|
||||
|
||||
<p>Backslash: <code>\\</code></p>
|
||||
|
||||
<p>Backtick: <code>\`</code></p>
|
||||
|
||||
<p>Asterisk: <code>\*</code></p>
|
||||
|
||||
<p>Underscore: <code>\_</code></p>
|
||||
|
||||
<p>Left brace: <code>\{</code></p>
|
||||
|
||||
<p>Right brace: <code>\}</code></p>
|
||||
|
||||
<p>Left bracket: <code>\[</code></p>
|
||||
|
||||
<p>Right bracket: <code>\]</code></p>
|
||||
|
||||
<p>Left paren: <code>\(</code></p>
|
||||
|
||||
<p>Right paren: <code>\)</code></p>
|
||||
|
||||
<p>Greater-than: <code>\></code></p>
|
||||
|
||||
<p>Hash: <code>\#</code></p>
|
||||
|
||||
<p>Period: <code>\.</code></p>
|
||||
|
||||
<p>Bang: <code>\!</code></p>
|
||||
|
||||
<p>Plus: <code>\+</code></p>
|
||||
|
||||
<p>Minus: <code>\-</code></p>
|
||||
|
||||
|
||||
<p>These should get escaped, even though they're matching pairs for
|
||||
other Markdown constructs:</p>
|
||||
|
||||
<p>*asterisks*</p>
|
||||
|
||||
<p>_underscores_</p>
|
||||
|
||||
<p>`backticks`</p>
|
||||
|
||||
<p>This is a code span with a literal backslash-backtick sequence: <code>\`</code></p>
|
||||
|
||||
<p>This is a tag with unescaped backticks <span attr='`ticks`'>bar</span>.</p>
|
||||
|
||||
<p>This is a tag with backslashes <span attr='\\backslashes\\'>bar</span>.</p>
|
@ -0,0 +1,120 @@
|
||||
These should all get escaped:
|
||||
|
||||
Backslash: \\
|
||||
|
||||
Backtick: \`
|
||||
|
||||
Asterisk: \*
|
||||
|
||||
Underscore: \_
|
||||
|
||||
Left brace: \{
|
||||
|
||||
Right brace: \}
|
||||
|
||||
Left bracket: \[
|
||||
|
||||
Right bracket: \]
|
||||
|
||||
Left paren: \(
|
||||
|
||||
Right paren: \)
|
||||
|
||||
Greater-than: \>
|
||||
|
||||
Hash: \#
|
||||
|
||||
Period: \.
|
||||
|
||||
Bang: \!
|
||||
|
||||
Plus: \+
|
||||
|
||||
Minus: \-
|
||||
|
||||
|
||||
|
||||
These should not, because they occur within a code block:
|
||||
|
||||
Backslash: \\
|
||||
|
||||
Backtick: \`
|
||||
|
||||
Asterisk: \*
|
||||
|
||||
Underscore: \_
|
||||
|
||||
Left brace: \{
|
||||
|
||||
Right brace: \}
|
||||
|
||||
Left bracket: \[
|
||||
|
||||
Right bracket: \]
|
||||
|
||||
Left paren: \(
|
||||
|
||||
Right paren: \)
|
||||
|
||||
Greater-than: \>
|
||||
|
||||
Hash: \#
|
||||
|
||||
Period: \.
|
||||
|
||||
Bang: \!
|
||||
|
||||
Plus: \+
|
||||
|
||||
Minus: \-
|
||||
|
||||
|
||||
Nor should these, which occur in code spans:
|
||||
|
||||
Backslash: `\\`
|
||||
|
||||
Backtick: `` \` ``
|
||||
|
||||
Asterisk: `\*`
|
||||
|
||||
Underscore: `\_`
|
||||
|
||||
Left brace: `\{`
|
||||
|
||||
Right brace: `\}`
|
||||
|
||||
Left bracket: `\[`
|
||||
|
||||
Right bracket: `\]`
|
||||
|
||||
Left paren: `\(`
|
||||
|
||||
Right paren: `\)`
|
||||
|
||||
Greater-than: `\>`
|
||||
|
||||
Hash: `\#`
|
||||
|
||||
Period: `\.`
|
||||
|
||||
Bang: `\!`
|
||||
|
||||
Plus: `\+`
|
||||
|
||||
Minus: `\-`
|
||||
|
||||
|
||||
These should get escaped, even though they're matching pairs for
|
||||
other Markdown constructs:
|
||||
|
||||
\*asterisks\*
|
||||
|
||||
\_underscores\_
|
||||
|
||||
\`backticks\`
|
||||
|
||||
This is a code span with a literal backslash-backtick sequence: `` \` ``
|
||||
|
||||
This is a tag with unescaped backticks <span attr='`ticks`'>bar</span>.
|
||||
|
||||
This is a tag with backslashes <span attr='\\backslashes\\'>bar</span>.
|
@ -0,0 +1,15 @@
|
||||
<blockquote>
|
||||
<p>Example:</p>
|
||||
|
||||
<pre><code>sub status {
|
||||
print "working";
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
<p>Or:</p>
|
||||
|
||||
<pre><code>sub status {
|
||||
return "working";
|
||||
}
|
||||
</code></pre>
|
||||
</blockquote>
|
@ -0,0 +1,11 @@
|
||||
> Example:
|
||||
>
|
||||
> sub status {
|
||||
> print "working";
|
||||
> }
|
||||
>
|
||||
> Or:
|
||||
>
|
||||
> sub status {
|
||||
> return "working";
|
||||
> }
|
@ -0,0 +1,18 @@
|
||||
<pre><code>code block on the first line
|
||||
</code></pre>
|
||||
|
||||
<p>Regular text.</p>
|
||||
|
||||
<pre><code>code block indented by spaces
|
||||
</code></pre>
|
||||
|
||||
<p>Regular text.</p>
|
||||
|
||||
<pre><code>the lines in this block
|
||||
all contain trailing spaces
|
||||
</code></pre>
|
||||
|
||||
<p>Regular Text.</p>
|
||||
|
||||
<pre><code>code block on the last line
|
||||
</code></pre>
|
@ -0,0 +1,14 @@
|
||||
code block on the first line
|
||||
|
||||
Regular text.
|
||||
|
||||
code block indented by spaces
|
||||
|
||||
Regular text.
|
||||
|
||||
the lines in this block
|
||||
all contain trailing spaces
|
||||
|
||||
Regular Text.
|
||||
|
||||
code block on the last line
|
@ -0,0 +1,6 @@
|
||||
<p><code><test a="</code> content of attribute <code>"></code></p>
|
||||
|
||||
<p>Fix for backticks within HTML tag: <span attr='`ticks`'>like this</span></p>
|
||||
|
||||
<p>Here's how you put <code>`backticks`</code> in a code span.</p>
|
||||
|
@ -0,0 +1,6 @@
|
||||
`<test a="` content of attribute `">`
|
||||
|
||||
Fix for backticks within HTML tag: <span attr='`ticks`'>like this</span>
|
||||
|
||||
Here's how you put `` `backticks` `` in a code span.
|
||||
|
@ -0,0 +1,8 @@
|
||||
<p>In Markdown 1.0.0 and earlier. Version
|
||||
8. This line turns into a list item.
|
||||
Because a hard-wrapped line in the
|
||||
middle of a paragraph looked like a
|
||||
list item.</p>
|
||||
|
||||
<p>Here's one with a bullet.
|
||||
* criminey.</p>
|
@ -0,0 +1,8 @@
|
||||
In Markdown 1.0.0 and earlier. Version
|
||||
8. This line turns into a list item.
|
||||
Because a hard-wrapped line in the
|
||||
middle of a paragraph looked like a
|
||||
list item.
|
||||
|
||||
Here's one with a bullet.
|
||||
* criminey.
|
@ -0,0 +1,71 @@
|
||||
<p>Dashes:</p>
|
||||
|
||||
<hr />
|
||||
|
||||
<hr />
|
||||
|
||||
<hr />
|
||||
|
||||
<hr />
|
||||
|
||||
<pre><code>---
|
||||
</code></pre>
|
||||
|
||||
<hr />
|
||||
|
||||
<hr />
|
||||
|
||||
<hr />
|
||||
|
||||
<hr />
|
||||
|
||||
<pre><code>- - -
|
||||
</code></pre>
|
||||
|
||||
<p>Asterisks:</p>
|
||||
|
||||
<hr />
|
||||
|
||||
<hr />
|
||||
|
||||
<hr />
|
||||
|
||||
<hr />
|
||||
|
||||
<pre><code>***
|
||||
</code></pre>
|
||||
|
||||
<hr />
|
||||
|
||||
<hr />
|
||||
|
||||
<hr />
|
||||
|
||||
<hr />
|
||||
|
||||
<pre><code>* * *
|
||||
</code></pre>
|
||||
|
||||
<p>Underscores:</p>
|
||||
|
||||
<hr />
|
||||
|
||||
<hr />
|
||||
|
||||
<hr />
|
||||
|
||||
<hr />
|
||||
|
||||
<pre><code>___
|
||||
</code></pre>
|
||||
|
||||
<hr />
|
||||
|
||||
<hr />
|
||||
|
||||
<hr />
|
||||
|
||||
<hr />
|
||||
|
||||
<pre><code>_ _ _
|
||||
</code></pre>
|
@ -0,0 +1,67 @@
|
||||
Dashes:
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
- - -
|
||||
|
||||
- - -
|
||||
|
||||
- - -
|
||||
|
||||
- - -
|
||||
|
||||
- - -
|
||||
|
||||
|
||||
Asterisks:
|
||||
|
||||
***
|
||||
|
||||
***
|
||||
|
||||
***
|
||||
|
||||
***
|
||||
|
||||
***
|
||||
|
||||
* * *
|
||||
|
||||
* * *
|
||||
|
||||
* * *
|
||||
|
||||
* * *
|
||||
|
||||
* * *
|
||||
|
||||
|
||||
Underscores:
|
||||
|
||||
___
|
||||
|
||||
___
|
||||
|
||||
___
|
||||
|
||||
___
|
||||
|
||||
___
|
||||
|
||||
_ _ _
|
||||
|
||||
_ _ _
|
||||
|
||||
_ _ _
|
||||
|
||||
_ _ _
|
||||
|
||||
_ _ _
|
@ -0,0 +1,15 @@
|
||||
<p>Simple block on one line:</p>
|
||||
|
||||
<div>foo</div>
|
||||
|
||||
<p>And nested without indentation:</p>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
foo
|
||||
</div>
|
||||
<div style=">"/>
|
||||
</div>
|
||||
<div>bar</div>
|
||||
</div>
|
@ -0,0 +1,15 @@
|
||||
Simple block on one line:
|
||||
|
||||
<div>foo</div>
|
||||
|
||||
And nested without indentation:
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
foo
|
||||
</div>
|
||||
<div style=">"/>
|
||||
</div>
|
||||
<div>bar</div>
|
||||
</div>
|
@ -0,0 +1,72 @@
|
||||
<p>Here's a simple block:</p>
|
||||
|
||||
<div>
|
||||
foo
|
||||
</div>
|
||||
|
||||
<p>This should be a code block, though:</p>
|
||||
|
||||
<pre><code><div>
|
||||
foo
|
||||
</div>
|
||||
</code></pre>
|
||||
|
||||
<p>As should this:</p>
|
||||
|
||||
<pre><code><div>foo</div>
|
||||
</code></pre>
|
||||
|
||||
<p>Now, nested:</p>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
foo
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>This should just be an HTML comment:</p>
|
||||
|
||||
<!-- Comment -->
|
||||
|
||||
<p>Multiline:</p>
|
||||
|
||||
<!--
|
||||
Blah
|
||||
Blah
|
||||
-->
|
||||
|
||||
<p>Code block:</p>
|
||||
|
||||
<pre><code><!-- Comment -->
|
||||
</code></pre>
|
||||
|
||||
<p>Just plain comment, with trailing spaces on the line:</p>
|
||||
|
||||
<!-- foo -->
|
||||
|
||||
<p>Code:</p>
|
||||
|
||||
<pre><code><hr />
|
||||
</code></pre>
|
||||
|
||||
<p>Hr's:</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<hr/>
|
||||
|
||||
<hr />
|
||||
|
||||
<hr>
|
||||
|
||||
<hr/>
|
||||
|
||||
<hr />
|
||||
|
||||
<hr class="foo" id="bar" />
|
||||
|
||||
<hr class="foo" id="bar"/>
|
||||
|
||||
<hr class="foo" id="bar" >
|
@ -0,0 +1,69 @@
|
||||
Here's a simple block:
|
||||
|
||||
<div>
|
||||
foo
|
||||
</div>
|
||||
|
||||
This should be a code block, though:
|
||||
|
||||
<div>
|
||||
foo
|
||||
</div>
|
||||
|
||||
As should this:
|
||||
|
||||
<div>foo</div>
|
||||
|
||||
Now, nested:
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
foo
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
This should just be an HTML comment:
|
||||
|
||||
<!-- Comment -->
|
||||
|
||||
Multiline:
|
||||
|
||||
<!--
|
||||
Blah
|
||||
Blah
|
||||
-->
|
||||
|
||||
Code block:
|
||||
|
||||
<!-- Comment -->
|
||||
|
||||
Just plain comment, with trailing spaces on the line:
|
||||
|
||||
<!-- foo -->
|
||||
|
||||
Code:
|
||||
|
||||
<hr />
|
||||
|
||||
Hr's:
|
||||
|
||||
<hr>
|
||||
|
||||
<hr/>
|
||||
|
||||
<hr />
|
||||
|
||||
<hr>
|
||||
|
||||
<hr/>
|
||||
|
||||
<hr />
|
||||
|
||||
<hr class="foo" id="bar" />
|
||||
|
||||
<hr class="foo" id="bar"/>
|
||||
|
||||
<hr class="foo" id="bar" >
|
||||
|
@ -0,0 +1,13 @@
|
||||
<p>Paragraph one.</p>
|
||||
|
||||
<!-- This is a simple comment -->
|
||||
|
||||
<!--
|
||||
This is another comment.
|
||||
-->
|
||||
|
||||
<p>Paragraph two.</p>
|
||||
|
||||
<!-- one comment block -- -- with two comments -->
|
||||
|
||||
<p>The end.</p>
|
@ -0,0 +1,13 @@
|
||||
Paragraph one.
|
||||
|
||||
<!-- This is a simple comment -->
|
||||
|
||||
<!--
|
||||
This is another comment.
|
||||
-->
|
||||
|
||||
Paragraph two.
|
||||
|
||||
<!-- one comment block -- -- with two comments -->
|
||||
|
||||
The end.
|
@ -0,0 +1,11 @@
|
||||
<p>Just a <a href="/url/">URL</a>.</p>
|
||||
|
||||
<p><a href="/url/" title="title">URL and title</a>.</p>
|
||||
|
||||
<p><a href="/url/" title="title preceded by two spaces">URL and title</a>.</p>
|
||||
|
||||
<p><a href="/url/" title="title preceded by a tab">URL and title</a>.</p>
|
||||
|
||||
<p><a href="/url/" title="title has spaces afterward">URL and title</a>.</p>
|
||||
|
||||
<p><a href="">Empty</a>.</p>
|
@ -0,0 +1,12 @@
|
||||
Just a [URL](/url/).
|
||||
|
||||
[URL and title](/url/ "title").
|
||||
|
||||
[URL and title](/url/ "title preceded by two spaces").
|
||||
|
||||
[URL and title](/url/ "title preceded by a tab").
|
||||
|
||||
[URL and title](/url/ "title has spaces afterward" ).
|
||||
|
||||
|
||||
[Empty]().
|
@ -0,0 +1,52 @@
|
||||
<p>Foo <a href="/url/" title="Title">bar</a>.</p>
|
||||
|
||||
<p>Foo <a href="/url/" title="Title">bar</a>.</p>
|
||||
|
||||
<p>Foo <a href="/url/" title="Title">bar</a>.</p>
|
||||
|
||||
<p>With <a href="/url/">embedded [brackets]</a>.</p>
|
||||
|
||||
<p>Indented <a href="/url">once</a>.</p>
|
||||
|
||||
<p>Indented <a href="/url">twice</a>.</p>
|
||||
|
||||
<p>Indented <a href="/url">thrice</a>.</p>
|
||||
|
||||
<p>Indented [four][] times.</p>
|
||||
|
||||
<pre><code>[four]: /url
|
||||
</code></pre>
|
||||
|
||||
<hr />
|
||||
|
||||
<p><a href="foo">this</a> should work</p>
|
||||
|
||||
<p>So should <a href="foo">this</a>.</p>
|
||||
|
||||
<p>And <a href="foo">this</a>.</p>
|
||||
|
||||
<p>And <a href="foo">this</a>.</p>
|
||||
|
||||
<p>And <a href="foo">this</a>.</p>
|
||||
|
||||
<p>But not [that] [].</p>
|
||||
|
||||
<p>Nor [that][].</p>
|
||||
|
||||
<p>Nor [that].</p>
|
||||
|
||||
<p>[Something in brackets like <a href="foo">this</a> should work]</p>
|
||||
|
||||
<p>[Same with <a href="foo">this</a>.]</p>
|
||||
|
||||
<p>In this case, <a href="/somethingelse/">this</a> points to something else.</p>
|
||||
|
||||
<p>Backslashing should suppress [this] and [this].</p>
|
||||
|
||||
<hr />
|
||||
|
||||
<p>Here's one where the <a href="/url/">link
|
||||
breaks</a> across lines.</p>
|
||||
|
||||
<p>Here's another where the <a href="/url/">link
|
||||
breaks</a> across lines, but with a line-ending space.</p>
|
@ -0,0 +1,71 @@
|
||||
Foo [bar] [1].
|
||||
|
||||
Foo [bar][1].
|
||||
|
||||
Foo [bar]
|
||||
[1].
|
||||
|
||||
[1]: /url/ "Title"
|
||||
|
||||
|
||||
With [embedded [brackets]] [b].
|
||||
|
||||
|
||||
Indented [once][].
|
||||
|
||||
Indented [twice][].
|
||||
|
||||
Indented [thrice][].
|
||||
|
||||
Indented [four][] times.
|
||||
|
||||
[once]: /url
|
||||
|
||||
[twice]: /url
|
||||
|
||||
[thrice]: /url
|
||||
|
||||
[four]: /url
|
||||
|
||||
|
||||
[b]: /url/
|
||||
|
||||
* * *
|
||||
|
||||
[this] [this] should work
|
||||
|
||||
So should [this][this].
|
||||
|
||||
And [this] [].
|
||||
|
||||
And [this][].
|
||||
|
||||
And [this].
|
||||
|
||||
But not [that] [].
|
||||
|
||||
Nor [that][].
|
||||
|
||||
Nor [that].
|
||||
|
||||
[Something in brackets like [this][] should work]
|
||||
|
||||
[Same with [this].]
|
||||
|
||||
In this case, [this](/somethingelse/) points to something else.
|
||||
|
||||
Backslashing should suppress \[this] and [this\].
|
||||
|
||||
[this]: foo
|
||||
|
||||
|
||||
* * *
|
||||
|
||||
Here's one where the [link
|
||||
breaks] across lines.
|
||||
|
||||
Here's another where the [link
|
||||
breaks] across lines, but with a line-ending space.
|
||||
|
||||
|
||||
[link breaks]: /url/
|
@ -0,0 +1,9 @@
|
||||
<p>This is the <a href="/simple">simple case</a>.</p>
|
||||
|
||||
<p>This one has a <a href="/foo">line
|
||||
break</a>.</p>
|
||||
|
||||
<p>This one has a <a href="/foo">line
|
||||
break</a> with a line-ending space.</p>
|
||||
|
||||
<p><a href="/that">this</a> and the <a href="/other">other</a></p>
|
@ -0,0 +1,20 @@
|
||||
This is the [simple case].
|
||||
|
||||
[simple case]: /simple
|
||||
|
||||
|
||||
|
||||
This one has a [line
|
||||
break].
|
||||
|
||||
This one has a [line
|
||||
break] with a line-ending space.
|
||||
|
||||
[line break]: /foo
|
||||
|
||||
|
||||
[this] [that] and the [other]
|
||||
|
||||
[this]: /this
|
||||
[that]: /that
|
||||
[other]: /other
|
@ -0,0 +1,3 @@
|
||||
<p>Foo <a href="/url/" title="Title with "quotes" inside">bar</a>.</p>
|
||||
|
||||
<p>Foo <a href="/url/" title="Title with "quotes" inside">bar</a>.</p>
|
@ -0,0 +1,7 @@
|
||||
Foo [bar][].
|
||||
|
||||
Foo [bar](/url/ "Title with "quotes" inside").
|
||||
|
||||
|
||||
[bar]: /url/ "Title with "quotes" inside"
|
||||
|
@ -0,0 +1,314 @@
|
||||
<h1>Markdown: Basics</h1>
|
||||
|
||||
<ul id="ProjectSubmenu">
|
||||
<li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li>
|
||||
<li><a class="selected" title="Markdown Basics">Basics</a></li>
|
||||
<li><a href="/projects/markdown/syntax" title="Markdown Syntax Documentation">Syntax</a></li>
|
||||
<li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li>
|
||||
<li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li>
|
||||
</ul>
|
||||
|
||||
<h2>Getting the Gist of Markdown's Formatting Syntax</h2>
|
||||
|
||||
<p>This page offers a brief overview of what it's like to use Markdown.
|
||||
The <a href="/projects/markdown/syntax" title="Markdown Syntax">syntax page</a> provides complete, detailed documentation for
|
||||
every feature, but Markdown should be very easy to pick up simply by
|
||||
looking at a few examples of it in action. The examples on this page
|
||||
are written in a before/after style, showing example syntax and the
|
||||
HTML output produced by Markdown.</p>
|
||||
|
||||
<p>It's also helpful to simply try Markdown out; the <a href="/projects/markdown/dingus" title="Markdown Dingus">Dingus</a> is a
|
||||
web application that allows you type your own Markdown-formatted text
|
||||
and translate it to XHTML.</p>
|
||||
|
||||
<p><strong>Note:</strong> This document is itself written using Markdown; you
|
||||
can <a href="/projects/markdown/basics.text">see the source for it by adding '.text' to the URL</a>.</p>
|
||||
|
||||
<h2>Paragraphs, Headers, Blockquotes</h2>
|
||||
|
||||
<p>A paragraph is simply one or more consecutive lines of text, separated
|
||||
by one or more blank lines. (A blank line is any line that looks like a
|
||||
blank line -- a line containing nothing spaces or tabs is considered
|
||||
blank.) Normal paragraphs should not be intended with spaces or tabs.</p>
|
||||
|
||||
<p>Markdown offers two styles of headers: <em>Setext</em> and <em>atx</em>.
|
||||
Setext-style headers for <code><h1></code> and <code><h2></code> are created by
|
||||
"underlining" with equal signs (<code>=</code>) and hyphens (<code>-</code>), respectively.
|
||||
To create an atx-style header, you put 1-6 hash marks (<code>#</code>) at the
|
||||
beginning of the line -- the number of hashes equals the resulting
|
||||
HTML header level.</p>
|
||||
|
||||
<p>Blockquotes are indicated using email-style '<code>></code>' angle brackets.</p>
|
||||
|
||||
<p>Markdown:</p>
|
||||
|
||||
<pre><code>A First Level Header
|
||||
====================
|
||||
|
||||
A Second Level Header
|
||||
---------------------
|
||||
|
||||
Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.
|
||||
|
||||
The quick brown fox jumped over the lazy
|
||||
dog's back.
|
||||
|
||||
### Header 3
|
||||
|
||||
> This is a blockquote.
|
||||
>
|
||||
> This is the second paragraph in the blockquote.
|
||||
>
|
||||
> ## This is an H2 in a blockquote
|
||||
</code></pre>
|
||||
|
||||
<p>Output:</p>
|
||||
|
||||
<pre><code><h1>A First Level Header</h1>
|
||||
|
||||
<h2>A Second Level Header</h2>
|
||||
|
||||
<p>Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.</p>
|
||||
|
||||
<p>The quick brown fox jumped over the lazy
|
||||
dog's back.</p>
|
||||
|
||||
<h3>Header 3</h3>
|
||||
|
||||
<blockquote>
|
||||
<p>This is a blockquote.</p>
|
||||
|
||||
<p>This is the second paragraph in the blockquote.</p>
|
||||
|
||||
<h2>This is an H2 in a blockquote</h2>
|
||||
</blockquote>
|
||||
</code></pre>
|
||||
|
||||
<h3>Phrase Emphasis</h3>
|
||||
|
||||
<p>Markdown uses asterisks and underscores to indicate spans of emphasis.</p>
|
||||
|
||||
<p>Markdown:</p>
|
||||
|
||||
<pre><code>Some of these words *are emphasized*.
|
||||
Some of these words _are emphasized also_.
|
||||
|
||||
Use two asterisks for **strong emphasis**.
|
||||
Or, if you prefer, __use two underscores instead__.
|
||||
</code></pre>
|
||||
|
||||
<p>Output:</p>
|
||||
|
||||
<pre><code><p>Some of these words <em>are emphasized</em>.
|
||||
Some of these words <em>are emphasized also</em>.</p>
|
||||
|
||||
<p>Use two asterisks for <strong>strong emphasis</strong>.
|
||||
Or, if you prefer, <strong>use two underscores instead</strong>.</p>
|
||||
</code></pre>
|
||||
|
||||
<h2>Lists</h2>
|
||||
|
||||
<p>Unordered (bulleted) lists use asterisks, pluses, and hyphens (<code>*</code>,
|
||||
<code>+</code>, and <code>-</code>) as list markers. These three markers are
|
||||
interchangable; this:</p>
|
||||
|
||||
<pre><code>* Candy.
|
||||
* Gum.
|
||||
* Booze.
|
||||
</code></pre>
|
||||
|
||||
<p>this:</p>
|
||||
|
||||
<pre><code>+ Candy.
|
||||
+ Gum.
|
||||
+ Booze.
|
||||
</code></pre>
|
||||
|
||||
<p>and this:</p>
|
||||
|
||||
<pre><code>- Candy.
|
||||
- Gum.
|
||||
- Booze.
|
||||
</code></pre>
|
||||
|
||||
<p>all produce the same output:</p>
|
||||
|
||||
<pre><code><ul>
|
||||
<li>Candy.</li>
|
||||
<li>Gum.</li>
|
||||
<li>Booze.</li>
|
||||
</ul>
|
||||
</code></pre>
|
||||
|
||||
<p>Ordered (numbered) lists use regular numbers, followed by periods, as
|
||||
list markers:</p>
|
||||
|
||||
<pre><code>1. Red
|
||||
2. Green
|
||||
3. Blue
|
||||
</code></pre>
|
||||
|
||||
<p>Output:</p>
|
||||
|
||||
<pre><code><ol>
|
||||
<li>Red</li>
|
||||
<li>Green</li>
|
||||
<li>Blue</li>
|
||||
</ol>
|
||||
</code></pre>
|
||||
|
||||
<p>If you put blank lines between items, you'll get <code><p></code> tags for the
|
||||
list item text. You can create multi-paragraph list items by indenting
|
||||
the paragraphs by 4 spaces or 1 tab:</p>
|
||||
|
||||
<pre><code>* A list item.
|
||||
|
||||
With multiple paragraphs.
|
||||
|
||||
* Another item in the list.
|
||||
</code></pre>
|
||||
|
||||
<p>Output:</p>
|
||||
|
||||
<pre><code><ul>
|
||||
<li><p>A list item.</p>
|
||||
<p>With multiple paragraphs.</p></li>
|
||||
<li><p>Another item in the list.</p></li>
|
||||
</ul>
|
||||
</code></pre>
|
||||
|
||||
<h3>Links</h3>
|
||||
|
||||
<p>Markdown supports two styles for creating links: <em>inline</em> and
|
||||
<em>reference</em>. With both styles, you use square brackets to delimit the
|
||||
text you want to turn into a link.</p>
|
||||
|
||||
<p>Inline-style links use parentheses immediately after the link text.
|
||||
For example:</p>
|
||||
|
||||
<pre><code>This is an [example link](http://example.com/).
|
||||
</code></pre>
|
||||
|
||||
<p>Output:</p>
|
||||
|
||||
<pre><code><p>This is an <a href="http://example.com/">
|
||||
example link</a>.</p>
|
||||
</code></pre>
|
||||
|
||||
<p>Optionally, you may include a title attribute in the parentheses:</p>
|
||||
|
||||
<pre><code>This is an [example link](http://example.com/ "With a Title").
|
||||
</code></pre>
|
||||
|
||||
<p>Output:</p>
|
||||
|
||||
<pre><code><p>This is an <a href="http://example.com/" title="With a Title">
|
||||
example link</a>.</p>
|
||||
</code></pre>
|
||||
|
||||
<p>Reference-style links allow you to refer to your links by names, which
|
||||
you define elsewhere in your document:</p>
|
||||
|
||||
<pre><code>I get 10 times more traffic from [Google][1] than from
|
||||
[Yahoo][2] or [MSN][3].
|
||||
|
||||
[1]: http://google.com/ "Google"
|
||||
[2]: http://search.yahoo.com/ "Yahoo Search"
|
||||
[3]: http://search.msn.com/ "MSN Search"
|
||||
</code></pre>
|
||||
|
||||
<p>Output:</p>
|
||||
|
||||
<pre><code><p>I get 10 times more traffic from <a href="http://google.com/"
|
||||
title="Google">Google</a> than from <a href="http://search.yahoo.com/"
|
||||
title="Yahoo Search">Yahoo</a> or <a href="http://search.msn.com/"
|
||||
title="MSN Search">MSN</a>.</p>
|
||||
</code></pre>
|
||||
|
||||
<p>The title attribute is optional. Link names may contain letters,
|
||||
numbers and spaces, but are <em>not</em> case sensitive:</p>
|
||||
|
||||
<pre><code>I start my morning with a cup of coffee and
|
||||
[The New York Times][NY Times].
|
||||
|
||||
[ny times]: http://www.nytimes.com/
|
||||
</code></pre>
|
||||
|
||||
<p>Output:</p>
|
||||
|
||||
<pre><code><p>I start my morning with a cup of coffee and
|
||||
<a href="http://www.nytimes.com/">The New York Times</a>.</p>
|
||||
</code></pre>
|
||||
|
||||
<h3>Images</h3>
|
||||
|
||||
<p>Image syntax is very much like link syntax.</p>
|
||||
|
||||
<p>Inline (titles are optional):</p>
|
||||
|
||||
<pre><code>![alt text](/path/to/img.jpg "Title")
|
||||
</code></pre>
|
||||
|
||||
<p>Reference-style:</p>
|
||||
|
||||
<pre><code>![alt text][id]
|
||||
|
||||
[id]: /path/to/img.jpg "Title"
|
||||
</code></pre>
|
||||
|
||||
<p>Both of the above examples produce the same output:</p>
|
||||
|
||||
<pre><code><img src="/path/to/img.jpg" alt="alt text" title="Title" />
|
||||
</code></pre>
|
||||
|
||||
<h3>Code</h3>
|
||||
|
||||
<p>In a regular paragraph, you can create code span by wrapping text in
|
||||
backtick quotes. Any ampersands (<code>&</code>) and angle brackets (<code><</code> or
|
||||
<code>></code>) will automatically be translated into HTML entities. This makes
|
||||
it easy to use Markdown to write about HTML example code:</p>
|
||||
|
||||
<pre><code>I strongly recommend against using any `<blink>` tags.
|
||||
|
||||
I wish SmartyPants used named entities like `&mdash;`
|
||||
instead of decimal-encoded entites like `&#8212;`.
|
||||
</code></pre>
|
||||
|
||||
<p>Output:</p>
|
||||
|
||||
<pre><code><p>I strongly recommend against using any
|
||||
<code>&lt;blink&gt;</code> tags.</p>
|
||||
|
||||
<p>I wish SmartyPants used named entities like
|
||||
<code>&amp;mdash;</code> instead of decimal-encoded
|
||||
entites like <code>&amp;#8212;</code>.</p>
|
||||
</code></pre>
|
||||
|
||||
<p>To specify an entire block of pre-formatted code, indent every line of
|
||||
the block by 4 spaces or 1 tab. Just like with code spans, <code>&</code>, <code><</code>,
|
||||
and <code>></code> characters will be escaped automatically.</p>
|
||||
|
||||
<p>Markdown:</p>
|
||||
|
||||
<pre><code>If you want your page to validate under XHTML 1.0 Strict,
|
||||
you've got to put paragraph tags in your blockquotes:
|
||||
|
||||
<blockquote>
|
||||
<p>For example.</p>
|
||||
</blockquote>
|
||||
</code></pre>
|
||||
|
||||
<p>Output:</p>
|
||||
|
||||
<pre><code><p>If you want your page to validate under XHTML 1.0 Strict,
|
||||
you've got to put paragraph tags in your blockquotes:</p>
|
||||
|
||||
<pre><code>&lt;blockquote&gt;
|
||||
&lt;p&gt;For example.&lt;/p&gt;
|
||||
&lt;/blockquote&gt;
|
||||
</code></pre>
|
||||
</code></pre>
|
@ -0,0 +1,306 @@
|
||||
Markdown: Basics
|
||||
================
|
||||
|
||||
<ul id="ProjectSubmenu">
|
||||
<li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li>
|
||||
<li><a class="selected" title="Markdown Basics">Basics</a></li>
|
||||
<li><a href="/projects/markdown/syntax" title="Markdown Syntax Documentation">Syntax</a></li>
|
||||
<li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li>
|
||||
<li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
Getting the Gist of Markdown's Formatting Syntax
|
||||
------------------------------------------------
|
||||
|
||||
This page offers a brief overview of what it's like to use Markdown.
|
||||
The [syntax page] [s] provides complete, detailed documentation for
|
||||
every feature, but Markdown should be very easy to pick up simply by
|
||||
looking at a few examples of it in action. The examples on this page
|
||||
are written in a before/after style, showing example syntax and the
|
||||
HTML output produced by Markdown.
|
||||
|
||||
It's also helpful to simply try Markdown out; the [Dingus] [d] is a
|
||||
web application that allows you type your own Markdown-formatted text
|
||||
and translate it to XHTML.
|
||||
|
||||
**Note:** This document is itself written using Markdown; you
|
||||
can [see the source for it by adding '.text' to the URL] [src].
|
||||
|
||||
[s]: /projects/markdown/syntax "Markdown Syntax"
|
||||
[d]: /projects/markdown/dingus "Markdown Dingus"
|
||||
[src]: /projects/markdown/basics.text
|
||||
|
||||
|
||||
## Paragraphs, Headers, Blockquotes ##
|
||||
|
||||
A paragraph is simply one or more consecutive lines of text, separated
|
||||
by one or more blank lines. (A blank line is any line that looks like a
|
||||
blank line -- a line containing nothing spaces or tabs is considered
|
||||
blank.) Normal paragraphs should not be intended with spaces or tabs.
|
||||
|
||||
Markdown offers two styles of headers: *Setext* and *atx*.
|
||||
Setext-style headers for `<h1>` and `<h2>` are created by
|
||||
"underlining" with equal signs (`=`) and hyphens (`-`), respectively.
|
||||
To create an atx-style header, you put 1-6 hash marks (`#`) at the
|
||||
beginning of the line -- the number of hashes equals the resulting
|
||||
HTML header level.
|
||||
|
||||
Blockquotes are indicated using email-style '`>`' angle brackets.
|
||||
|
||||
Markdown:
|
||||
|
||||
A First Level Header
|
||||
====================
|
||||
|
||||
A Second Level Header
|
||||
---------------------
|
||||
|
||||
Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.
|
||||
|
||||
The quick brown fox jumped over the lazy
|
||||
dog's back.
|
||||
|
||||
### Header 3
|
||||
|
||||
> This is a blockquote.
|
||||
>
|
||||
> This is the second paragraph in the blockquote.
|
||||
>
|
||||
> ## This is an H2 in a blockquote
|
||||
|
||||
|
||||
Output:
|
||||
|
||||
<h1>A First Level Header</h1>
|
||||
|
||||
<h2>A Second Level Header</h2>
|
||||
|
||||
<p>Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.</p>
|
||||
|
||||
<p>The quick brown fox jumped over the lazy
|
||||
dog's back.</p>
|
||||
|
||||
<h3>Header 3</h3>
|
||||
|
||||
<blockquote>
|
||||
<p>This is a blockquote.</p>
|
||||
|
||||
<p>This is the second paragraph in the blockquote.</p>
|
||||
|
||||
<h2>This is an H2 in a blockquote</h2>
|
||||
</blockquote>
|
||||
|
||||
|
||||
|
||||
### Phrase Emphasis ###
|
||||
|
||||
Markdown uses asterisks and underscores to indicate spans of emphasis.
|
||||
|
||||
Markdown:
|
||||
|
||||
Some of these words *are emphasized*.
|
||||
Some of these words _are emphasized also_.
|
||||
|
||||
Use two asterisks for **strong emphasis**.
|
||||
Or, if you prefer, __use two underscores instead__.
|
||||
|
||||
Output:
|
||||
|
||||
<p>Some of these words <em>are emphasized</em>.
|
||||
Some of these words <em>are emphasized also</em>.</p>
|
||||
|
||||
<p>Use two asterisks for <strong>strong emphasis</strong>.
|
||||
Or, if you prefer, <strong>use two underscores instead</strong>.</p>
|
||||
|
||||
|
||||
|
||||
## Lists ##
|
||||
|
||||
Unordered (bulleted) lists use asterisks, pluses, and hyphens (`*`,
|
||||
`+`, and `-`) as list markers. These three markers are
|
||||
interchangable; this:
|
||||
|
||||
* Candy.
|
||||
* Gum.
|
||||
* Booze.
|
||||
|
||||
this:
|
||||
|
||||
+ Candy.
|
||||
+ Gum.
|
||||
+ Booze.
|
||||
|
||||
and this:
|
||||
|
||||
- Candy.
|
||||
- Gum.
|
||||
- Booze.
|
||||
|
||||
all produce the same output:
|
||||
|
||||
<ul>
|
||||
<li>Candy.</li>
|
||||
<li>Gum.</li>
|
||||
<li>Booze.</li>
|
||||
</ul>
|
||||
|
||||
Ordered (numbered) lists use regular numbers, followed by periods, as
|
||||
list markers:
|
||||
|
||||
1. Red
|
||||
2. Green
|
||||
3. Blue
|
||||
|
||||
Output:
|
||||
|
||||
<ol>
|
||||
<li>Red</li>
|
||||
<li>Green</li>
|
||||
<li>Blue</li>
|
||||
</ol>
|
||||
|
||||
If you put blank lines between items, you'll get `<p>` tags for the
|
||||
list item text. You can create multi-paragraph list items by indenting
|
||||
the paragraphs by 4 spaces or 1 tab:
|
||||
|
||||
* A list item.
|
||||
|
||||
With multiple paragraphs.
|
||||
|
||||
* Another item in the list.
|
||||
|
||||
Output:
|
||||
|
||||
<ul>
|
||||
<li><p>A list item.</p>
|
||||
<p>With multiple paragraphs.</p></li>
|
||||
<li><p>Another item in the list.</p></li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
### Links ###
|
||||
|
||||
Markdown supports two styles for creating links: *inline* and
|
||||
*reference*. With both styles, you use square brackets to delimit the
|
||||
text you want to turn into a link.
|
||||
|
||||
Inline-style links use parentheses immediately after the link text.
|
||||
For example:
|
||||
|
||||
This is an [example link](http://example.com/).
|
||||
|
||||
Output:
|
||||
|
||||
<p>This is an <a href="http://example.com/">
|
||||
example link</a>.</p>
|
||||
|
||||
Optionally, you may include a title attribute in the parentheses:
|
||||
|
||||
This is an [example link](http://example.com/ "With a Title").
|
||||
|
||||
Output:
|
||||
|
||||
<p>This is an <a href="http://example.com/" title="With a Title">
|
||||
example link</a>.</p>
|
||||
|
||||
Reference-style links allow you to refer to your links by names, which
|
||||
you define elsewhere in your document:
|
||||
|
||||
I get 10 times more traffic from [Google][1] than from
|
||||
[Yahoo][2] or [MSN][3].
|
||||
|
||||
[1]: http://google.com/ "Google"
|
||||
[2]: http://search.yahoo.com/ "Yahoo Search"
|
||||
[3]: http://search.msn.com/ "MSN Search"
|
||||
|
||||
Output:
|
||||
|
||||
<p>I get 10 times more traffic from <a href="http://google.com/"
|
||||
title="Google">Google</a> than from <a href="http://search.yahoo.com/"
|
||||
title="Yahoo Search">Yahoo</a> or <a href="http://search.msn.com/"
|
||||
title="MSN Search">MSN</a>.</p>
|
||||
|
||||
The title attribute is optional. Link names may contain letters,
|
||||
numbers and spaces, but are *not* case sensitive:
|
||||
|
||||
I start my morning with a cup of coffee and
|
||||
[The New York Times][NY Times].
|
||||
|
||||
[ny times]: http://www.nytimes.com/
|
||||
|
||||
Output:
|
||||
|
||||
<p>I start my morning with a cup of coffee and
|
||||
<a href="http://www.nytimes.com/">The New York Times</a>.</p>
|
||||
|
||||
|
||||
### Images ###
|
||||
|
||||
Image syntax is very much like link syntax.
|
||||
|
||||
Inline (titles are optional):
|
||||
|
||||
![alt text](/path/to/img.jpg "Title")
|
||||
|
||||
Reference-style:
|
||||
|
||||
![alt text][id]
|
||||
|
||||
[id]: /path/to/img.jpg "Title"
|
||||
|
||||
Both of the above examples produce the same output:
|
||||
|
||||
<img src="/path/to/img.jpg" alt="alt text" title="Title" />
|
||||
|
||||
|
||||
|
||||
### Code ###
|
||||
|
||||
In a regular paragraph, you can create code span by wrapping text in
|
||||
backtick quotes. Any ampersands (`&`) and angle brackets (`<` or
|
||||
`>`) will automatically be translated into HTML entities. This makes
|
||||
it easy to use Markdown to write about HTML example code:
|
||||
|
||||
I strongly recommend against using any `<blink>` tags.
|
||||
|
||||
I wish SmartyPants used named entities like `—`
|
||||
instead of decimal-encoded entites like `—`.
|
||||
|
||||
Output:
|
||||
|
||||
<p>I strongly recommend against using any
|
||||
<code><blink></code> tags.</p>
|
||||
|
||||
<p>I wish SmartyPants used named entities like
|
||||
<code>&mdash;</code> instead of decimal-encoded
|
||||
entites like <code>&#8212;</code>.</p>
|
||||
|
||||
|
||||
To specify an entire block of pre-formatted code, indent every line of
|
||||
the block by 4 spaces or 1 tab. Just like with code spans, `&`, `<`,
|
||||
and `>` characters will be escaped automatically.
|
||||
|
||||
Markdown:
|
||||
|
||||
If you want your page to validate under XHTML 1.0 Strict,
|
||||
you've got to put paragraph tags in your blockquotes:
|
||||
|
||||
<blockquote>
|
||||
<p>For example.</p>
|
||||
</blockquote>
|
||||
|
||||
Output:
|
||||
|
||||
<p>If you want your page to validate under XHTML 1.0 Strict,
|
||||
you've got to put paragraph tags in your blockquotes:</p>
|
||||
|
||||
<pre><code><blockquote>
|
||||
<p>For example.</p>
|
||||
</blockquote>
|
||||
</code></pre>
|
@ -0,0 +1,942 @@
|
||||
<h1>Markdown: Syntax</h1>
|
||||
|
||||
<ul id="ProjectSubmenu">
|
||||
<li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li>
|
||||
<li><a href="/projects/markdown/basics" title="Markdown Basics">Basics</a></li>
|
||||
<li><a class="selected" title="Markdown Syntax Documentation">Syntax</a></li>
|
||||
<li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li>
|
||||
<li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li>
|
||||
</ul>
|
||||
|
||||
<ul>
|
||||
<li><a href="#overview">Overview</a>
|
||||
<ul>
|
||||
<li><a href="#philosophy">Philosophy</a></li>
|
||||
<li><a href="#html">Inline HTML</a></li>
|
||||
<li><a href="#autoescape">Automatic Escaping for Special Characters</a></li>
|
||||
</ul></li>
|
||||
<li><a href="#block">Block Elements</a>
|
||||
<ul>
|
||||
<li><a href="#p">Paragraphs and Line Breaks</a></li>
|
||||
<li><a href="#header">Headers</a></li>
|
||||
<li><a href="#blockquote">Blockquotes</a></li>
|
||||
<li><a href="#list">Lists</a></li>
|
||||
<li><a href="#precode">Code Blocks</a></li>
|
||||
<li><a href="#hr">Horizontal Rules</a></li>
|
||||
</ul></li>
|
||||
<li><a href="#span">Span Elements</a>
|
||||
<ul>
|
||||
<li><a href="#link">Links</a></li>
|
||||
<li><a href="#em">Emphasis</a></li>
|
||||
<li><a href="#code">Code</a></li>
|
||||
<li><a href="#img">Images</a></li>
|
||||
</ul></li>
|
||||
<li><a href="#misc">Miscellaneous</a>
|
||||
<ul>
|
||||
<li><a href="#backslash">Backslash Escapes</a></li>
|
||||
<li><a href="#autolink">Automatic Links</a></li>
|
||||
</ul></li>
|
||||
</ul>
|
||||
|
||||
<p><strong>Note:</strong> This document is itself written using Markdown; you
|
||||
can <a href="/projects/markdown/syntax.text">see the source for it by adding '.text' to the URL</a>.</p>
|
||||
|
||||
<hr />
|
||||
|
||||
<h2 id="overview">Overview</h2>
|
||||
|
||||
<h3 id="philosophy">Philosophy</h3>
|
||||
|
||||
<p>Markdown is intended to be as easy-to-read and easy-to-write as is feasible.</p>
|
||||
|
||||
<p>Readability, however, is emphasized above all else. A Markdown-formatted
|
||||
document should be publishable as-is, as plain text, without looking
|
||||
like it's been marked up with tags or formatting instructions. While
|
||||
Markdown's syntax has been influenced by several existing text-to-HTML
|
||||
filters -- including <a href="http://docutils.sourceforge.net/mirror/setext.html">Setext</a>, <a href="http://www.aaronsw.com/2002/atx/">atx</a>, <a href="http://textism.com/tools/textile/">Textile</a>, <a href="http://docutils.sourceforge.net/rst.html">reStructuredText</a>,
|
||||
<a href="http://www.triptico.com/software/grutatxt.html">Grutatext</a>, and <a href="http://ettext.taint.org/doc/">EtText</a> -- the single biggest source of
|
||||
inspiration for Markdown's syntax is the format of plain text email.</p>
|
||||
|
||||
<p>To this end, Markdown's syntax is comprised entirely of punctuation
|
||||
characters, which punctuation characters have been carefully chosen so
|
||||
as to look like what they mean. E.g., asterisks around a word actually
|
||||
look like *emphasis*. Markdown lists look like, well, lists. Even
|
||||
blockquotes look like quoted passages of text, assuming you've ever
|
||||
used email.</p>
|
||||
|
||||
<h3 id="html">Inline HTML</h3>
|
||||
|
||||
<p>Markdown's syntax is intended for one purpose: to be used as a
|
||||
format for <em>writing</em> for the web.</p>
|
||||
|
||||
<p>Markdown is not a replacement for HTML, or even close to it. Its
|
||||
syntax is very small, corresponding only to a very small subset of
|
||||
HTML tags. The idea is <em>not</em> to create a syntax that makes it easier
|
||||
to insert HTML tags. In my opinion, HTML tags are already easy to
|
||||
insert. The idea for Markdown is to make it easy to read, write, and
|
||||
edit prose. HTML is a <em>publishing</em> format; Markdown is a <em>writing</em>
|
||||
format. Thus, Markdown's formatting syntax only addresses issues that
|
||||
can be conveyed in plain text.</p>
|
||||
|
||||
<p>For any markup that is not covered by Markdown's syntax, you simply
|
||||
use HTML itself. There's no need to preface it or delimit it to
|
||||
indicate that you're switching from Markdown to HTML; you just use
|
||||
the tags.</p>
|
||||
|
||||
<p>The only restrictions are that block-level HTML elements -- e.g. <code><div></code>,
|
||||
<code><table></code>, <code><pre></code>, <code><p></code>, etc. -- must be separated from surrounding
|
||||
content by blank lines, and the start and end tags of the block should
|
||||
not be indented with tabs or spaces. Markdown is smart enough not
|
||||
to add extra (unwanted) <code><p></code> tags around HTML block-level tags.</p>
|
||||
|
||||
<p>For example, to add an HTML table to a Markdown article:</p>
|
||||
|
||||
<pre><code>This is a regular paragraph.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>Foo</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
This is another regular paragraph.
|
||||
</code></pre>
|
||||
|
||||
<p>Note that Markdown formatting syntax is not processed within block-level
|
||||
HTML tags. E.g., you can't use Markdown-style <code>*emphasis*</code> inside an
|
||||
HTML block.</p>
|
||||
|
||||
<p>Span-level HTML tags -- e.g. <code><span></code>, <code><cite></code>, or <code><del></code> -- can be
|
||||
used anywhere in a Markdown paragraph, list item, or header. If you
|
||||
want, you can even use HTML tags instead of Markdown formatting; e.g. if
|
||||
you'd prefer to use HTML <code><a></code> or <code><img></code> tags instead of Markdown's
|
||||
link or image syntax, go right ahead.</p>
|
||||
|
||||
<p>Unlike block-level HTML tags, Markdown syntax <em>is</em> processed within
|
||||
span-level tags.</p>
|
||||
|
||||
<h3 id="autoescape">Automatic Escaping for Special Characters</h3>
|
||||
|
||||
<p>In HTML, there are two characters that demand special treatment: <code><</code>
|
||||
and <code>&</code>. Left angle brackets are used to start tags; ampersands are
|
||||
used to denote HTML entities. If you want to use them as literal
|
||||
characters, you must escape them as entities, e.g. <code>&lt;</code>, and
|
||||
<code>&amp;</code>.</p>
|
||||
|
||||
<p>Ampersands in particular are bedeviling for web writers. If you want to
|
||||
write about 'AT&T', you need to write '<code>AT&amp;T</code>'. You even need to
|
||||
escape ampersands within URLs. Thus, if you want to link to:</p>
|
||||
|
||||
<pre><code>http://images.google.com/images?num=30&q=larry+bird
|
||||
</code></pre>
|
||||
|
||||
<p>you need to encode the URL as:</p>
|
||||
|
||||
<pre><code>http://images.google.com/images?num=30&amp;q=larry+bird
|
||||
</code></pre>
|
||||
|
||||
<p>in your anchor tag <code>href</code> attribute. Needless to say, this is easy to
|
||||
forget, and is probably the single most common source of HTML validation
|
||||
errors in otherwise well-marked-up web sites.</p>
|
||||
|
||||
<p>Markdown allows you to use these characters naturally, taking care of
|
||||
all the necessary escaping for you. If you use an ampersand as part of
|
||||
an HTML entity, it remains unchanged; otherwise it will be translated
|
||||
into <code>&amp;</code>.</p>
|
||||
|
||||
<p>So, if you want to include a copyright symbol in your article, you can write:</p>
|
||||
|
||||
<pre><code>&copy;
|
||||
</code></pre>
|
||||
|
||||
<p>and Markdown will leave it alone. But if you write:</p>
|
||||
|
||||
<pre><code>AT&T
|
||||
</code></pre>
|
||||
|
||||
<p>Markdown will translate it to:</p>
|
||||
|
||||
<pre><code>AT&amp;T
|
||||
</code></pre>
|
||||
|
||||
<p>Similarly, because Markdown supports <a href="#html">inline HTML</a>, if you use
|
||||
angle brackets as delimiters for HTML tags, Markdown will treat them as
|
||||
such. But if you write:</p>
|
||||
|
||||
<pre><code>4 < 5
|
||||
</code></pre>
|
||||
|
||||
<p>Markdown will translate it to:</p>
|
||||
|
||||
<pre><code>4 &lt; 5
|
||||
</code></pre>
|
||||
|
||||
<p>However, inside Markdown code spans and blocks, angle brackets and
|
||||
ampersands are <em>always</em> encoded automatically. This makes it easy to use
|
||||
Markdown to write about HTML code. (As opposed to raw HTML, which is a
|
||||
terrible format for writing about HTML syntax, because every single <code><</code>
|
||||
and <code>&</code> in your example code needs to be escaped.)</p>
|
||||
|
||||
<hr />
|
||||
|
||||
<h2 id="block">Block Elements</h2>
|
||||
|
||||
<h3 id="p">Paragraphs and Line Breaks</h3>
|
||||
|
||||
<p>A paragraph is simply one or more consecutive lines of text, separated
|
||||
by one or more blank lines. (A blank line is any line that looks like a
|
||||
blank line -- a line containing nothing but spaces or tabs is considered
|
||||
blank.) Normal paragraphs should not be intended with spaces or tabs.</p>
|
||||
|
||||
<p>The implication of the "one or more consecutive lines of text" rule is
|
||||
that Markdown supports "hard-wrapped" text paragraphs. This differs
|
||||
significantly from most other text-to-HTML formatters (including Movable
|
||||
Type's "Convert Line Breaks" option) which translate every line break
|
||||
character in a paragraph into a <code><br /></code> tag.</p>
|
||||
|
||||
<p>When you <em>do</em> want to insert a <code><br /></code> break tag using Markdown, you
|
||||
end a line with two or more spaces, then type return.</p>
|
||||
|
||||
<p>Yes, this takes a tad more effort to create a <code><br /></code>, but a simplistic
|
||||
"every line break is a <code><br /></code>" rule wouldn't work for Markdown.
|
||||
Markdown's email-style <a href="#blockquote">blockquoting</a> and multi-paragraph <a href="#list">list items</a>
|
||||
work best -- and look better -- when you format them with hard breaks.</p>
|
||||
|
||||
<h3 id="header">Headers</h3>
|
||||
|
||||
<p>Markdown supports two styles of headers, <a href="http://docutils.sourceforge.net/mirror/setext.html">Setext</a> and <a href="http://www.aaronsw.com/2002/atx/">atx</a>.</p>
|
||||
|
||||
<p>Setext-style headers are "underlined" using equal signs (for first-level
|
||||
headers) and dashes (for second-level headers). For example:</p>
|
||||
|
||||
<pre><code>This is an H1
|
||||
=============
|
||||
|
||||
This is an H2
|
||||
-------------
|
||||
</code></pre>
|
||||
|
||||
<p>Any number of underlining <code>=</code>'s or <code>-</code>'s will work.</p>
|
||||
|
||||
<p>Atx-style headers use 1-6 hash characters at the start of the line,
|
||||
corresponding to header levels 1-6. For example:</p>
|
||||
|
||||
<pre><code># This is an H1
|
||||
|
||||
## This is an H2
|
||||
|
||||
###### This is an H6
|
||||
</code></pre>
|
||||
|
||||
<p>Optionally, you may "close" atx-style headers. This is purely
|
||||
cosmetic -- you can use this if you think it looks better. The
|
||||
closing hashes don't even need to match the number of hashes
|
||||
used to open the header. (The number of opening hashes
|
||||
determines the header level.) :</p>
|
||||
|
||||
<pre><code># This is an H1 #
|
||||
|
||||
## This is an H2 ##
|
||||
|
||||
### This is an H3 ######
|
||||
</code></pre>
|
||||
|
||||
<h3 id="blockquote">Blockquotes</h3>
|
||||
|
||||
<p>Markdown uses email-style <code>></code> characters for blockquoting. If you're
|
||||
familiar with quoting passages of text in an email message, then you
|
||||
know how to create a blockquote in Markdown. It looks best if you hard
|
||||
wrap the text and put a <code>></code> before every line:</p>
|
||||
|
||||
<pre><code>> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
|
||||
> consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
|
||||
> Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
|
||||
>
|
||||
> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
|
||||
> id sem consectetuer libero luctus adipiscing.
|
||||
</code></pre>
|
||||
|
||||
<p>Markdown allows you to be lazy and only put the <code>></code> before the first
|
||||
line of a hard-wrapped paragraph:</p>
|
||||
|
||||
<pre><code>> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
|
||||
consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
|
||||
Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
|
||||
|
||||
> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
|
||||
id sem consectetuer libero luctus adipiscing.
|
||||
</code></pre>
|
||||
|
||||
<p>Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by
|
||||
adding additional levels of <code>></code>:</p>
|
||||
|
||||
<pre><code>> This is the first level of quoting.
|
||||
>
|
||||
> > This is nested blockquote.
|
||||
>
|
||||
> Back to the first level.
|
||||
</code></pre>
|
||||
|
||||
<p>Blockquotes can contain other Markdown elements, including headers, lists,
|
||||
and code blocks:</p>
|
||||
|
||||
<pre><code>> ## This is a header.
|
||||
>
|
||||
> 1. This is the first list item.
|
||||
> 2. This is the second list item.
|
||||
>
|
||||
> Here's some example code:
|
||||
>
|
||||
> return shell_exec("echo $input | $markdown_script");
|
||||
</code></pre>
|
||||
|
||||
<p>Any decent text editor should make email-style quoting easy. For
|
||||
example, with BBEdit, you can make a selection and choose Increase
|
||||
Quote Level from the Text menu.</p>
|
||||
|
||||
<h3 id="list">Lists</h3>
|
||||
|
||||
<p>Markdown supports ordered (numbered) and unordered (bulleted) lists.</p>
|
||||
|
||||
<p>Unordered lists use asterisks, pluses, and hyphens -- interchangably
|
||||
-- as list markers:</p>
|
||||
|
||||
<pre><code>* Red
|
||||
* Green
|
||||
* Blue
|
||||
</code></pre>
|
||||
|
||||
<p>is equivalent to:</p>
|
||||
|
||||
<pre><code>+ Red
|
||||
+ Green
|
||||
+ Blue
|
||||
</code></pre>
|
||||
|
||||
<p>and:</p>
|
||||
|
||||
<pre><code>- Red
|
||||
- Green
|
||||
- Blue
|
||||
</code></pre>
|
||||
|
||||
<p>Ordered lists use numbers followed by periods:</p>
|
||||
|
||||
<pre><code>1. Bird
|
||||
2. McHale
|
||||
3. Parish
|
||||
</code></pre>
|
||||
|
||||
<p>It's important to note that the actual numbers you use to mark the
|
||||
list have no effect on the HTML output Markdown produces. The HTML
|
||||
Markdown produces from the above list is:</p>
|
||||
|
||||
<pre><code><ol>
|
||||
<li>Bird</li>
|
||||
<li>McHale</li>
|
||||
<li>Parish</li>
|
||||
</ol>
|
||||
</code></pre>
|
||||
|
||||
<p>If you instead wrote the list in Markdown like this:</p>
|
||||
|
||||
<pre><code>1. Bird
|
||||
1. McHale
|
||||
1. Parish
|
||||
</code></pre>
|
||||
|
||||
<p>or even:</p>
|
||||
|
||||
<pre><code>3. Bird
|
||||
1. McHale
|
||||
8. Parish
|
||||
</code></pre>
|
||||
|
||||
<p>you'd get the exact same HTML output. The point is, if you want to,
|
||||
you can use ordinal numbers in your ordered Markdown lists, so that
|
||||
the numbers in your source match the numbers in your published HTML.
|
||||
But if you want to be lazy, you don't have to.</p>
|
||||
|
||||
<p>If you do use lazy list numbering, however, you should still start the
|
||||
list with the number 1. At some point in the future, Markdown may support
|
||||
starting ordered lists at an arbitrary number.</p>
|
||||
|
||||
<p>List markers typically start at the left margin, but may be indented by
|
||||
up to three spaces. List markers must be followed by one or more spaces
|
||||
or a tab.</p>
|
||||
|
||||
<p>To make lists look nice, you can wrap items with hanging indents:</p>
|
||||
|
||||
<pre><code>* Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
|
||||
Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
|
||||
viverra nec, fringilla in, laoreet vitae, risus.
|
||||
* Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
|
||||
Suspendisse id sem consectetuer libero luctus adipiscing.
|
||||
</code></pre>
|
||||
|
||||
<p>But if you want to be lazy, you don't have to:</p>
|
||||
|
||||
<pre><code>* Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
|
||||
Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
|
||||
viverra nec, fringilla in, laoreet vitae, risus.
|
||||
* Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
|
||||
Suspendisse id sem consectetuer libero luctus adipiscing.
|
||||
</code></pre>
|
||||
|
||||
<p>If list items are separated by blank lines, Markdown will wrap the
|
||||
items in <code><p></code> tags in the HTML output. For example, this input:</p>
|
||||
|
||||
<pre><code>* Bird
|
||||
* Magic
|
||||
</code></pre>
|
||||
|
||||
<p>will turn into:</p>
|
||||
|
||||
<pre><code><ul>
|
||||
<li>Bird</li>
|
||||
<li>Magic</li>
|
||||
</ul>
|
||||
</code></pre>
|
||||
|
||||
<p>But this:</p>
|
||||
|
||||
<pre><code>* Bird
|
||||
|
||||
* Magic
|
||||
</code></pre>
|
||||
|
||||
<p>will turn into:</p>
|
||||
|
||||
<pre><code><ul>
|
||||
<li><p>Bird</p></li>
|
||||
<li><p>Magic</p></li>
|
||||
</ul>
|
||||
</code></pre>
|
||||
|
||||
<p>List items may consist of multiple paragraphs. Each subsequent
|
||||
paragraph in a list item must be intended by either 4 spaces
|
||||
or one tab:</p>
|
||||
|
||||
<pre><code>1. This is a list item with two paragraphs. Lorem ipsum dolor
|
||||
sit amet, consectetuer adipiscing elit. Aliquam hendrerit
|
||||
mi posuere lectus.
|
||||
|
||||
Vestibulum enim wisi, viverra nec, fringilla in, laoreet
|
||||
vitae, risus. Donec sit amet nisl. Aliquam semper ipsum
|
||||
sit amet velit.
|
||||
|
||||
2. Suspendisse id sem consectetuer libero luctus adipiscing.
|
||||
</code></pre>
|
||||
|
||||
<p>It looks nice if you indent every line of the subsequent
|
||||
paragraphs, but here again, Markdown will allow you to be
|
||||
lazy:</p>
|
||||
|
||||
<pre><code>* This is a list item with two paragraphs.
|
||||
|
||||
This is the second paragraph in the list item. You're
|
||||
only required to indent the first line. Lorem ipsum dolor
|
||||
sit amet, consectetuer adipiscing elit.
|
||||
|
||||
* Another item in the same list.
|
||||
</code></pre>
|
||||
|
||||
<p>To put a blockquote within a list item, the blockquote's <code>></code>
|
||||
delimiters need to be indented:</p>
|
||||
|
||||
<pre><code>* A list item with a blockquote:
|
||||
|
||||
> This is a blockquote
|
||||
> inside a list item.
|
||||
</code></pre>
|
||||
|
||||
<p>To put a code block within a list item, the code block needs
|
||||
to be indented <em>twice</em> -- 8 spaces or two tabs:</p>
|
||||
|
||||
<pre><code>* A list item with a code block:
|
||||
|
||||
<code goes here>
|
||||
</code></pre>
|
||||
|
||||
<p>It's worth noting that it's possible to trigger an ordered list by
|
||||
accident, by writing something like this:</p>
|
||||
|
||||
<pre><code>1986. What a great season.
|
||||
</code></pre>
|
||||
|
||||
<p>In other words, a <em>number-period-space</em> sequence at the beginning of a
|
||||
line. To avoid this, you can backslash-escape the period:</p>
|
||||
|
||||
<pre><code>1986\. What a great season.
|
||||
</code></pre>
|
||||
|
||||
<h3 id="precode">Code Blocks</h3>
|
||||
|
||||
<p>Pre-formatted code blocks are used for writing about programming or
|
||||
markup source code. Rather than forming normal paragraphs, the lines
|
||||
of a code block are interpreted literally. Markdown wraps a code block
|
||||
in both <code><pre></code> and <code><code></code> tags.</p>
|
||||
|
||||
<p>To produce a code block in Markdown, simply indent every line of the
|
||||
block by at least 4 spaces or 1 tab. For example, given this input:</p>
|
||||
|
||||
<pre><code>This is a normal paragraph:
|
||||
|
||||
This is a code block.
|
||||
</code></pre>
|
||||
|
||||
<p>Markdown will generate:</p>
|
||||
|
||||
<pre><code><p>This is a normal paragraph:</p>
|
||||
|
||||
<pre><code>This is a code block.
|
||||
</code></pre>
|
||||
</code></pre>
|
||||
|
||||
<p>One level of indentation -- 4 spaces or 1 tab -- is removed from each
|
||||
line of the code block. For example, this:</p>
|
||||
|
||||
<pre><code>Here is an example of AppleScript:
|
||||
|
||||
tell application "Foo"
|
||||
beep
|
||||
end tell
|
||||
</code></pre>
|
||||
|
||||
<p>will turn into:</p>
|
||||
|
||||
<pre><code><p>Here is an example of AppleScript:</p>
|
||||
|
||||
<pre><code>tell application "Foo"
|
||||
beep
|
||||
end tell
|
||||
</code></pre>
|
||||
</code></pre>
|
||||
|
||||
<p>A code block continues until it reaches a line that is not indented
|
||||
(or the end of the article).</p>
|
||||
|
||||
<p>Within a code block, ampersands (<code>&</code>) and angle brackets (<code><</code> and <code>></code>)
|
||||
are automatically converted into HTML entities. This makes it very
|
||||
easy to include example HTML source code using Markdown -- just paste
|
||||
it and indent it, and Markdown will handle the hassle of encoding the
|
||||
ampersands and angle brackets. For example, this:</p>
|
||||
|
||||
<pre><code> <div class="footer">
|
||||
&copy; 2004 Foo Corporation
|
||||
</div>
|
||||
</code></pre>
|
||||
|
||||
<p>will turn into:</p>
|
||||
|
||||
<pre><code><pre><code>&lt;div class="footer"&gt;
|
||||
&amp;copy; 2004 Foo Corporation
|
||||
&lt;/div&gt;
|
||||
</code></pre>
|
||||
</code></pre>
|
||||
|
||||
<p>Regular Markdown syntax is not processed within code blocks. E.g.,
|
||||
asterisks are just literal asterisks within a code block. This means
|
||||
it's also easy to use Markdown to write about Markdown's own syntax.</p>
|
||||
|
||||
<h3 id="hr">Horizontal Rules</h3>
|
||||
|
||||
<p>You can produce a horizontal rule tag (<code><hr /></code>) by placing three or
|
||||
more hyphens, asterisks, or underscores on a line by themselves. If you
|
||||
wish, you may use spaces between the hyphens or asterisks. Each of the
|
||||
following lines will produce a horizontal rule:</p>
|
||||
|
||||
<pre><code>* * *
|
||||
|
||||
***
|
||||
|
||||
*****
|
||||
|
||||
- - -
|
||||
|
||||
---------------------------------------
|
||||
|
||||
_ _ _
|
||||
</code></pre>
|
||||
|
||||
<hr />
|
||||
|
||||
<h2 id="span">Span Elements</h2>
|
||||
|
||||
<h3 id="link">Links</h3>
|
||||
|
||||
<p>Markdown supports two style of links: <em>inline</em> and <em>reference</em>.</p>
|
||||
|
||||
<p>In both styles, the link text is delimited by [square brackets].</p>
|
||||
|
||||
<p>To create an inline link, use a set of regular parentheses immediately
|
||||
after the link text's closing square bracket. Inside the parentheses,
|
||||
put the URL where you want the link to point, along with an <em>optional</em>
|
||||
title for the link, surrounded in quotes. For example:</p>
|
||||
|
||||
<pre><code>This is [an example](http://example.com/ "Title") inline link.
|
||||
|
||||
[This link](http://example.net/) has no title attribute.
|
||||
</code></pre>
|
||||
|
||||
<p>Will produce:</p>
|
||||
|
||||
<pre><code><p>This is <a href="http://example.com/" title="Title">
|
||||
an example</a> inline link.</p>
|
||||
|
||||
<p><a href="http://example.net/">This link</a> has no
|
||||
title attribute.</p>
|
||||
</code></pre>
|
||||
|
||||
<p>If you're referring to a local resource on the same server, you can
|
||||
use relative paths:</p>
|
||||
|
||||
<pre><code>See my [About](/about/) page for details.
|
||||
</code></pre>
|
||||
|
||||
<p>Reference-style links use a second set of square brackets, inside
|
||||
which you place a label of your choosing to identify the link:</p>
|
||||
|
||||
<pre><code>This is [an example][id] reference-style link.
|
||||
</code></pre>
|
||||
|
||||
<p>You can optionally use a space to separate the sets of brackets:</p>
|
||||
|
||||
<pre><code>This is [an example] [id] reference-style link.
|
||||
</code></pre>
|
||||
|
||||
<p>Then, anywhere in the document, you define your link label like this,
|
||||
on a line by itself:</p>
|
||||
|
||||
<pre><code>[id]: http://example.com/ "Optional Title Here"
|
||||
</code></pre>
|
||||
|
||||
<p>That is:</p>
|
||||
|
||||
<ul>
|
||||
<li>Square brackets containing the link identifier (optionally
|
||||
indented from the left margin using up to three spaces);</li>
|
||||
<li>followed by a colon;</li>
|
||||
<li>followed by one or more spaces (or tabs);</li>
|
||||
<li>followed by the URL for the link;</li>
|
||||
<li>optionally followed by a title attribute for the link, enclosed
|
||||
in double or single quotes.</li>
|
||||
</ul>
|
||||
|
||||
<p>The link URL may, optionally, be surrounded by angle brackets:</p>
|
||||
|
||||
<pre><code>[id]: <http://example.com/> "Optional Title Here"
|
||||
</code></pre>
|
||||
|
||||
<p>You can put the title attribute on the next line and use extra spaces
|
||||
or tabs for padding, which tends to look better with longer URLs:</p>
|
||||
|
||||
<pre><code>[id]: http://example.com/longish/path/to/resource/here
|
||||
"Optional Title Here"
|
||||
</code></pre>
|
||||
|
||||
<p>Link definitions are only used for creating links during Markdown
|
||||
processing, and are stripped from your document in the HTML output.</p>
|
||||
|
||||
<p>Link definition names may constist of letters, numbers, spaces, and punctuation -- but they are <em>not</em> case sensitive. E.g. these two links:</p>
|
||||
|
||||
<pre><code>[link text][a]
|
||||
[link text][A]
|
||||
</code></pre>
|
||||
|
||||
<p>are equivalent.</p>
|
||||
|
||||
<p>The <em>implicit link name</em> shortcut allows you to omit the name of the
|
||||
link, in which case the link text itself is used as the name.
|
||||
Just use an empty set of square brackets -- e.g., to link the word
|
||||
"Google" to the google.com web site, you could simply write:</p>
|
||||
|
||||
<pre><code>[Google][]
|
||||
</code></pre>
|
||||
|
||||
<p>And then define the link:</p>
|
||||
|
||||
<pre><code>[Google]: http://google.com/
|
||||
</code></pre>
|
||||
|
||||
<p>Because link names may contain spaces, this shortcut even works for
|
||||
multiple words in the link text:</p>
|
||||
|
||||
<pre><code>Visit [Daring Fireball][] for more information.
|
||||
</code></pre>
|
||||
|
||||
<p>And then define the link:</p>
|
||||
|
||||
<pre><code>[Daring Fireball]: http://daringfireball.net/
|
||||
</code></pre>
|
||||
|
||||
<p>Link definitions can be placed anywhere in your Markdown document. I
|
||||
tend to put them immediately after each paragraph in which they're
|
||||
used, but if you want, you can put them all at the end of your
|
||||
document, sort of like footnotes.</p>
|
||||
|
||||
<p>Here's an example of reference links in action:</p>
|
||||
|
||||
<pre><code>I get 10 times more traffic from [Google] [1] than from
|
||||
[Yahoo] [2] or [MSN] [3].
|
||||
|
||||
[1]: http://google.com/ "Google"
|
||||
[2]: http://search.yahoo.com/ "Yahoo Search"
|
||||
[3]: http://search.msn.com/ "MSN Search"
|
||||
</code></pre>
|
||||
|
||||
<p>Using the implicit link name shortcut, you could instead write:</p>
|
||||
|
||||
<pre><code>I get 10 times more traffic from [Google][] than from
|
||||
[Yahoo][] or [MSN][].
|
||||
|
||||
[google]: http://google.com/ "Google"
|
||||
[yahoo]: http://search.yahoo.com/ "Yahoo Search"
|
||||
[msn]: http://search.msn.com/ "MSN Search"
|
||||
</code></pre>
|
||||
|
||||
<p>Both of the above examples will produce the following HTML output:</p>
|
||||
|
||||
<pre><code><p>I get 10 times more traffic from <a href="http://google.com/"
|
||||
title="Google">Google</a> than from
|
||||
<a href="http://search.yahoo.com/" title="Yahoo Search">Yahoo</a>
|
||||
or <a href="http://search.msn.com/" title="MSN Search">MSN</a>.</p>
|
||||
</code></pre>
|
||||
|
||||
<p>For comparison, here is the same paragraph written using
|
||||
Markdown's inline link style:</p>
|
||||
|
||||
<pre><code>I get 10 times more traffic from [Google](http://google.com/ "Google")
|
||||
than from [Yahoo](http://search.yahoo.com/ "Yahoo Search") or
|
||||
[MSN](http://search.msn.com/ "MSN Search").
|
||||
</code></pre>
|
||||
|
||||
<p>The point of reference-style links is not that they're easier to
|
||||
write. The point is that with reference-style links, your document
|
||||
source is vastly more readable. Compare the above examples: using
|
||||
reference-style links, the paragraph itself is only 81 characters
|
||||
long; with inline-style links, it's 176 characters; and as raw HTML,
|
||||
it's 234 characters. In the raw HTML, there's more markup than there
|
||||
is text.</p>
|
||||
|
||||
<p>With Markdown's reference-style links, a source document much more
|
||||
closely resembles the final output, as rendered in a browser. By
|
||||
allowing you to move the markup-related metadata out of the paragraph,
|
||||
you can add links without interrupting the narrative flow of your
|
||||
prose.</p>
|
||||
|
||||
<h3 id="em">Emphasis</h3>
|
||||
|
||||
<p>Markdown treats asterisks (<code>*</code>) and underscores (<code>_</code>) as indicators of
|
||||
emphasis. Text wrapped with one <code>*</code> or <code>_</code> will be wrapped with an
|
||||
HTML <code><em></code> tag; double <code>*</code>'s or <code>_</code>'s will be wrapped with an HTML
|
||||
<code><strong></code> tag. E.g., this input:</p>
|
||||
|
||||
<pre><code>*single asterisks*
|
||||
|
||||
_single underscores_
|
||||
|
||||
**double asterisks**
|
||||
|
||||
__double underscores__
|
||||
</code></pre>
|
||||
|
||||
<p>will produce:</p>
|
||||
|
||||
<pre><code><em>single asterisks</em>
|
||||
|
||||
<em>single underscores</em>
|
||||
|
||||
<strong>double asterisks</strong>
|
||||
|
||||
<strong>double underscores</strong>
|
||||
</code></pre>
|
||||
|
||||
<p>You can use whichever style you prefer; the lone restriction is that
|
||||
the same character must be used to open and close an emphasis span.</p>
|
||||
|
||||
<p>Emphasis can be used in the middle of a word:</p>
|
||||
|
||||
<pre><code>un*fucking*believable
|
||||
</code></pre>
|
||||
|
||||
<p>But if you surround an <code>*</code> or <code>_</code> with spaces, it'll be treated as a
|
||||
literal asterisk or underscore.</p>
|
||||
|
||||
<p>To produce a literal asterisk or underscore at a position where it
|
||||
would otherwise be used as an emphasis delimiter, you can backslash
|
||||
escape it:</p>
|
||||
|
||||
<pre><code>\*this text is surrounded by literal asterisks\*
|
||||
</code></pre>
|
||||
|
||||
<h3 id="code">Code</h3>
|
||||
|
||||
<p>To indicate a span of code, wrap it with backtick quotes (<code>`</code>).
|
||||
Unlike a pre-formatted code block, a code span indicates code within a
|
||||
normal paragraph. For example:</p>
|
||||
|
||||
<pre><code>Use the `printf()` function.
|
||||
</code></pre>
|
||||
|
||||
<p>will produce:</p>
|
||||
|
||||
<pre><code><p>Use the <code>printf()</code> function.</p>
|
||||
</code></pre>
|
||||
|
||||
<p>To include a literal backtick character within a code span, you can use
|
||||
multiple backticks as the opening and closing delimiters:</p>
|
||||
|
||||
<pre><code>``There is a literal backtick (`) here.``
|
||||
</code></pre>
|
||||
|
||||
<p>which will produce this:</p>
|
||||
|
||||
<pre><code><p><code>There is a literal backtick (`) here.</code></p>
|
||||
</code></pre>
|
||||
|
||||
<p>The backtick delimiters surrounding a code span may include spaces --
|
||||
one after the opening, one before the closing. This allows you to place
|
||||
literal backtick characters at the beginning or end of a code span:</p>
|
||||
|
||||
<pre><code>A single backtick in a code span: `` ` ``
|
||||
|
||||
A backtick-delimited string in a code span: `` `foo` ``
|
||||
</code></pre>
|
||||
|
||||
<p>will produce:</p>
|
||||
|
||||
<pre><code><p>A single backtick in a code span: <code>`</code></p>
|
||||
|
||||
<p>A backtick-delimited string in a code span: <code>`foo`</code></p>
|
||||
</code></pre>
|
||||
|
||||
<p>With a code span, ampersands and angle brackets are encoded as HTML
|
||||
entities automatically, which makes it easy to include example HTML
|
||||
tags. Markdown will turn this:</p>
|
||||
|
||||
<pre><code>Please don't use any `<blink>` tags.
|
||||
</code></pre>
|
||||
|
||||
<p>into:</p>
|
||||
|
||||
<pre><code><p>Please don't use any <code>&lt;blink&gt;</code> tags.</p>
|
||||
</code></pre>
|
||||
|
||||
<p>You can write this:</p>
|
||||
|
||||
<pre><code>`&#8212;` is the decimal-encoded equivalent of `&mdash;`.
|
||||
</code></pre>
|
||||
|
||||
<p>to produce:</p>
|
||||
|
||||
<pre><code><p><code>&amp;#8212;</code> is the decimal-encoded
|
||||
equivalent of <code>&amp;mdash;</code>.</p>
|
||||
</code></pre>
|
||||
|
||||
<h3 id="img">Images</h3>
|
||||
|
||||
<p>Admittedly, it's fairly difficult to devise a "natural" syntax for
|
||||
placing images into a plain text document format.</p>
|
||||
|
||||
<p>Markdown uses an image syntax that is intended to resemble the syntax
|
||||
for links, allowing for two styles: <em>inline</em> and <em>reference</em>.</p>
|
||||
|
||||
<p>Inline image syntax looks like this:</p>
|
||||
|
||||
<pre><code>![Alt text](/path/to/img.jpg)
|
||||
|
||||
![Alt text](/path/to/img.jpg "Optional title")
|
||||
</code></pre>
|
||||
|
||||
<p>That is:</p>
|
||||
|
||||
<ul>
|
||||
<li>An exclamation mark: <code>!</code>;</li>
|
||||
<li>followed by a set of square brackets, containing the <code>alt</code>
|
||||
attribute text for the image;</li>
|
||||
<li>followed by a set of parentheses, containing the URL or path to
|
||||
the image, and an optional <code>title</code> attribute enclosed in double
|
||||
or single quotes.</li>
|
||||
</ul>
|
||||
|
||||
<p>Reference-style image syntax looks like this:</p>
|
||||
|
||||
<pre><code>![Alt text][id]
|
||||
</code></pre>
|
||||
|
||||
<p>Where "id" is the name of a defined image reference. Image references
|
||||
are defined using syntax identical to link references:</p>
|
||||
|
||||
<pre><code>[id]: url/to/image "Optional title attribute"
|
||||
</code></pre>
|
||||
|
||||
<p>As of this writing, Markdown has no syntax for specifying the
|
||||
dimensions of an image; if this is important to you, you can simply
|
||||
use regular HTML <code><img></code> tags.</p>
|
||||
|
||||
<hr />
|
||||
|
||||
<h2 id="misc">Miscellaneous</h2>
|
||||
|
||||
<h3 id="autolink">Automatic Links</h3>
|
||||
|
||||
<p>Markdown supports a shortcut style for creating "automatic" links for URLs and email addresses: simply surround the URL or email address with angle brackets. What this means is that if you want to show the actual text of a URL or email address, and also have it be a clickable link, you can do this:</p>
|
||||
|
||||
<pre><code><http://example.com/>
|
||||
</code></pre>
|
||||
|
||||
<p>Markdown will turn this into:</p>
|
||||
|
||||
<pre><code><a href="http://example.com/">http://example.com/</a>
|
||||
</code></pre>
|
||||
|
||||
<p>Automatic links for email addresses work similarly, except that
|
||||
Markdown will also perform a bit of randomized decimal and hex
|
||||
entity-encoding to help obscure your address from address-harvesting
|
||||
spambots. For example, Markdown will turn this:</p>
|
||||
|
||||
<pre><code><address@example.com>
|
||||
</code></pre>
|
||||
|
||||
<p>into something like this:</p>
|
||||
|
||||
<pre><code><a href="&#x6D;&#x61;i&#x6C;&#x74;&#x6F;:&#x61;&#x64;&#x64;&#x72;&#x65;
|
||||
&#115;&#115;&#64;&#101;&#120;&#x61;&#109;&#x70;&#x6C;e&#x2E;&#99;&#111;
|
||||
&#109;">&#x61;&#x64;&#x64;&#x72;&#x65;&#115;&#115;&#64;&#101;&#120;&#x61;
|
||||
&#109;&#x70;&#x6C;e&#x2E;&#99;&#111;&#109;</a>
|
||||
</code></pre>
|
||||
|
||||
<p>which will render in a browser as a clickable link to "address@example.com".</p>
|
||||
|
||||
<p>(This sort of entity-encoding trick will indeed fool many, if not
|
||||
most, address-harvesting bots, but it definitely won't fool all of
|
||||
them. It's better than nothing, but an address published in this way
|
||||
will probably eventually start receiving spam.)</p>
|
||||
|
||||
<h3 id="backslash">Backslash Escapes</h3>
|
||||
|
||||
<p>Markdown allows you to use backslash escapes to generate literal
|
||||
characters which would otherwise have special meaning in Markdown's
|
||||
formatting syntax. For example, if you wanted to surround a word with
|
||||
literal asterisks (instead of an HTML <code><em></code> tag), you can backslashes
|
||||
before the asterisks, like this:</p>
|
||||
|
||||
<pre><code>\*literal asterisks\*
|
||||
</code></pre>
|
||||
|
||||
<p>Markdown provides backslash escapes for the following characters:</p>
|
||||
|
||||
<pre><code>\ backslash
|
||||
` backtick
|
||||
* asterisk
|
||||
_ underscore
|
||||
{} curly braces
|
||||
[] square brackets
|
||||
() parentheses
|
||||
# hash mark
|
||||
+ plus sign
|
||||
- minus sign (hyphen)
|
||||
. dot
|
||||
! exclamation mark
|
||||
</code></pre>
|
@ -0,0 +1,888 @@
|
||||
Markdown: Syntax
|
||||
================
|
||||
|
||||
<ul id="ProjectSubmenu">
|
||||
<li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li>
|
||||
<li><a href="/projects/markdown/basics" title="Markdown Basics">Basics</a></li>
|
||||
<li><a class="selected" title="Markdown Syntax Documentation">Syntax</a></li>
|
||||
<li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li>
|
||||
<li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
* [Overview](#overview)
|
||||
* [Philosophy](#philosophy)
|
||||
* [Inline HTML](#html)
|
||||
* [Automatic Escaping for Special Characters](#autoescape)
|
||||
* [Block Elements](#block)
|
||||
* [Paragraphs and Line Breaks](#p)
|
||||
* [Headers](#header)
|
||||
* [Blockquotes](#blockquote)
|
||||
* [Lists](#list)
|
||||
* [Code Blocks](#precode)
|
||||
* [Horizontal Rules](#hr)
|
||||
* [Span Elements](#span)
|
||||
* [Links](#link)
|
||||
* [Emphasis](#em)
|
||||
* [Code](#code)
|
||||
* [Images](#img)
|
||||
* [Miscellaneous](#misc)
|
||||
* [Backslash Escapes](#backslash)
|
||||
* [Automatic Links](#autolink)
|
||||
|
||||
|
||||
**Note:** This document is itself written using Markdown; you
|
||||
can [see the source for it by adding '.text' to the URL][src].
|
||||
|
||||
[src]: /projects/markdown/syntax.text
|
||||
|
||||
* * *
|
||||
|
||||
<h2 id="overview">Overview</h2>
|
||||
|
||||
<h3 id="philosophy">Philosophy</h3>
|
||||
|
||||
Markdown is intended to be as easy-to-read and easy-to-write as is feasible.
|
||||
|
||||
Readability, however, is emphasized above all else. A Markdown-formatted
|
||||
document should be publishable as-is, as plain text, without looking
|
||||
like it's been marked up with tags or formatting instructions. While
|
||||
Markdown's syntax has been influenced by several existing text-to-HTML
|
||||
filters -- including [Setext] [1], [atx] [2], [Textile] [3], [reStructuredText] [4],
|
||||
[Grutatext] [5], and [EtText] [6] -- the single biggest source of
|
||||
inspiration for Markdown's syntax is the format of plain text email.
|
||||
|
||||
[1]: http://docutils.sourceforge.net/mirror/setext.html
|
||||
[2]: http://www.aaronsw.com/2002/atx/
|
||||
[3]: http://textism.com/tools/textile/
|
||||
[4]: http://docutils.sourceforge.net/rst.html
|
||||
[5]: http://www.triptico.com/software/grutatxt.html
|
||||
[6]: http://ettext.taint.org/doc/
|
||||
|
||||
To this end, Markdown's syntax is comprised entirely of punctuation
|
||||
characters, which punctuation characters have been carefully chosen so
|
||||
as to look like what they mean. E.g., asterisks around a word actually
|
||||
look like \*emphasis\*. Markdown lists look like, well, lists. Even
|
||||
blockquotes look like quoted passages of text, assuming you've ever
|
||||
used email.
|
||||
|
||||
|
||||
|
||||
<h3 id="html">Inline HTML</h3>
|
||||
|
||||
Markdown's syntax is intended for one purpose: to be used as a
|
||||
format for *writing* for the web.
|
||||
|
||||
Markdown is not a replacement for HTML, or even close to it. Its
|
||||
syntax is very small, corresponding only to a very small subset of
|
||||
HTML tags. The idea is *not* to create a syntax that makes it easier
|
||||
to insert HTML tags. In my opinion, HTML tags are already easy to
|
||||
insert. The idea for Markdown is to make it easy to read, write, and
|
||||
edit prose. HTML is a *publishing* format; Markdown is a *writing*
|
||||
format. Thus, Markdown's formatting syntax only addresses issues that
|
||||
can be conveyed in plain text.
|
||||
|
||||
For any markup that is not covered by Markdown's syntax, you simply
|
||||
use HTML itself. There's no need to preface it or delimit it to
|
||||
indicate that you're switching from Markdown to HTML; you just use
|
||||
the tags.
|
||||
|
||||
The only restrictions are that block-level HTML elements -- e.g. `<div>`,
|
||||
`<table>`, `<pre>`, `<p>`, etc. -- must be separated from surrounding
|
||||
content by blank lines, and the start and end tags of the block should
|
||||
not be indented with tabs or spaces. Markdown is smart enough not
|
||||
to add extra (unwanted) `<p>` tags around HTML block-level tags.
|
||||
|
||||
For example, to add an HTML table to a Markdown article:
|
||||
|
||||
This is a regular paragraph.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>Foo</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
This is another regular paragraph.
|
||||
|
||||
Note that Markdown formatting syntax is not processed within block-level
|
||||
HTML tags. E.g., you can't use Markdown-style `*emphasis*` inside an
|
||||
HTML block.
|
||||
|
||||
Span-level HTML tags -- e.g. `<span>`, `<cite>`, or `<del>` -- can be
|
||||
used anywhere in a Markdown paragraph, list item, or header. If you
|
||||
want, you can even use HTML tags instead of Markdown formatting; e.g. if
|
||||
you'd prefer to use HTML `<a>` or `<img>` tags instead of Markdown's
|
||||
link or image syntax, go right ahead.
|
||||
|
||||
Unlike block-level HTML tags, Markdown syntax *is* processed within
|
||||
span-level tags.
|
||||
|
||||
|
||||
<h3 id="autoescape">Automatic Escaping for Special Characters</h3>
|
||||
|
||||
In HTML, there are two characters that demand special treatment: `<`
|
||||
and `&`. Left angle brackets are used to start tags; ampersands are
|
||||
used to denote HTML entities. If you want to use them as literal
|
||||
characters, you must escape them as entities, e.g. `<`, and
|
||||
`&`.
|
||||
|
||||
Ampersands in particular are bedeviling for web writers. If you want to
|
||||
write about 'AT&T', you need to write '`AT&T`'. You even need to
|
||||
escape ampersands within URLs. Thus, if you want to link to:
|
||||
|
||||
http://images.google.com/images?num=30&q=larry+bird
|
||||
|
||||
you need to encode the URL as:
|
||||
|
||||
http://images.google.com/images?num=30&q=larry+bird
|
||||
|
||||
in your anchor tag `href` attribute. Needless to say, this is easy to
|
||||
forget, and is probably the single most common source of HTML validation
|
||||
errors in otherwise well-marked-up web sites.
|
||||
|
||||
Markdown allows you to use these characters naturally, taking care of
|
||||
all the necessary escaping for you. If you use an ampersand as part of
|
||||
an HTML entity, it remains unchanged; otherwise it will be translated
|
||||
into `&`.
|
||||
|
||||
So, if you want to include a copyright symbol in your article, you can write:
|
||||
|
||||
©
|
||||
|
||||
and Markdown will leave it alone. But if you write:
|
||||
|
||||
AT&T
|
||||
|
||||
Markdown will translate it to:
|
||||
|
||||
AT&T
|
||||
|
||||
Similarly, because Markdown supports [inline HTML](#html), if you use
|
||||
angle brackets as delimiters for HTML tags, Markdown will treat them as
|
||||
such. But if you write:
|
||||
|
||||
4 < 5
|
||||
|
||||
Markdown will translate it to:
|
||||
|
||||
4 < 5
|
||||
|
||||
However, inside Markdown code spans and blocks, angle brackets and
|
||||
ampersands are *always* encoded automatically. This makes it easy to use
|
||||
Markdown to write about HTML code. (As opposed to raw HTML, which is a
|
||||
terrible format for writing about HTML syntax, because every single `<`
|
||||
and `&` in your example code needs to be escaped.)
|
||||
|
||||
|
||||
* * *
|
||||
|
||||
|
||||
<h2 id="block">Block Elements</h2>
|
||||
|
||||
|
||||
<h3 id="p">Paragraphs and Line Breaks</h3>
|
||||
|
||||
A paragraph is simply one or more consecutive lines of text, separated
|
||||
by one or more blank lines. (A blank line is any line that looks like a
|
||||
blank line -- a line containing nothing but spaces or tabs is considered
|
||||
blank.) Normal paragraphs should not be intended with spaces or tabs.
|
||||
|
||||
The implication of the "one or more consecutive lines of text" rule is
|
||||
that Markdown supports "hard-wrapped" text paragraphs. This differs
|
||||
significantly from most other text-to-HTML formatters (including Movable
|
||||
Type's "Convert Line Breaks" option) which translate every line break
|
||||
character in a paragraph into a `<br />` tag.
|
||||
|
||||
When you *do* want to insert a `<br />` break tag using Markdown, you
|
||||
end a line with two or more spaces, then type return.
|
||||
|
||||
Yes, this takes a tad more effort to create a `<br />`, but a simplistic
|
||||
"every line break is a `<br />`" rule wouldn't work for Markdown.
|
||||
Markdown's email-style [blockquoting][bq] and multi-paragraph [list items][l]
|
||||
work best -- and look better -- when you format them with hard breaks.
|
||||
|
||||
[bq]: #blockquote
|
||||
[l]: #list
|
||||
|
||||
|
||||
|
||||
<h3 id="header">Headers</h3>
|
||||
|
||||
Markdown supports two styles of headers, [Setext] [1] and [atx] [2].
|
||||
|
||||
Setext-style headers are "underlined" using equal signs (for first-level
|
||||
headers) and dashes (for second-level headers). For example:
|
||||
|
||||
This is an H1
|
||||
=============
|
||||
|
||||
This is an H2
|
||||
-------------
|
||||
|
||||
Any number of underlining `=`'s or `-`'s will work.
|
||||
|
||||
Atx-style headers use 1-6 hash characters at the start of the line,
|
||||
corresponding to header levels 1-6. For example:
|
||||
|
||||
# This is an H1
|
||||
|
||||
## This is an H2
|
||||
|
||||
###### This is an H6
|
||||
|
||||
Optionally, you may "close" atx-style headers. This is purely
|
||||
cosmetic -- you can use this if you think it looks better. The
|
||||
closing hashes don't even need to match the number of hashes
|
||||
used to open the header. (The number of opening hashes
|
||||
determines the header level.) :
|
||||
|
||||
# This is an H1 #
|
||||
|
||||
## This is an H2 ##
|
||||
|
||||
### This is an H3 ######
|
||||
|
||||
|
||||
<h3 id="blockquote">Blockquotes</h3>
|
||||
|
||||
Markdown uses email-style `>` characters for blockquoting. If you're
|
||||
familiar with quoting passages of text in an email message, then you
|
||||
know how to create a blockquote in Markdown. It looks best if you hard
|
||||
wrap the text and put a `>` before every line:
|
||||
|
||||
> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
|
||||
> consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
|
||||
> Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
|
||||
>
|
||||
> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
|
||||
> id sem consectetuer libero luctus adipiscing.
|
||||
|
||||
Markdown allows you to be lazy and only put the `>` before the first
|
||||
line of a hard-wrapped paragraph:
|
||||
|
||||
> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
|
||||
consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
|
||||
Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
|
||||
|
||||
> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
|
||||
id sem consectetuer libero luctus adipiscing.
|
||||
|
||||
Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by
|
||||
adding additional levels of `>`:
|
||||
|
||||
> This is the first level of quoting.
|
||||
>
|
||||
> > This is nested blockquote.
|
||||
>
|
||||
> Back to the first level.
|
||||
|
||||
Blockquotes can contain other Markdown elements, including headers, lists,
|
||||
and code blocks:
|
||||
|
||||
> ## This is a header.
|
||||
>
|
||||
> 1. This is the first list item.
|
||||
> 2. This is the second list item.
|
||||
>
|
||||
> Here's some example code:
|
||||
>
|
||||
> return shell_exec("echo $input | $markdown_script");
|
||||
|
||||
Any decent text editor should make email-style quoting easy. For
|
||||
example, with BBEdit, you can make a selection and choose Increase
|
||||
Quote Level from the Text menu.
|
||||
|
||||
|
||||
<h3 id="list">Lists</h3>
|
||||
|
||||
Markdown supports ordered (numbered) and unordered (bulleted) lists.
|
||||
|
||||
Unordered lists use asterisks, pluses, and hyphens -- interchangably
|
||||
-- as list markers:
|
||||
|
||||
* Red
|
||||
* Green
|
||||
* Blue
|
||||
|
||||
is equivalent to:
|
||||
|
||||
+ Red
|
||||
+ Green
|
||||
+ Blue
|
||||
|
||||
and:
|
||||
|
||||
- Red
|
||||
- Green
|
||||
- Blue
|
||||
|
||||
Ordered lists use numbers followed by periods:
|
||||
|
||||
1. Bird
|
||||
2. McHale
|
||||
3. Parish
|
||||
|
||||
It's important to note that the actual numbers you use to mark the
|
||||
list have no effect on the HTML output Markdown produces. The HTML
|
||||
Markdown produces from the above list is:
|
||||
|
||||
<ol>
|
||||
<li>Bird</li>
|
||||
<li>McHale</li>
|
||||
<li>Parish</li>
|
||||
</ol>
|
||||
|
||||
If you instead wrote the list in Markdown like this:
|
||||
|
||||
1. Bird
|
||||
1. McHale
|
||||
1. Parish
|
||||
|
||||
or even:
|
||||
|
||||
3. Bird
|
||||
1. McHale
|
||||
8. Parish
|
||||
|
||||
you'd get the exact same HTML output. The point is, if you want to,
|
||||
you can use ordinal numbers in your ordered Markdown lists, so that
|
||||
the numbers in your source match the numbers in your published HTML.
|
||||
But if you want to be lazy, you don't have to.
|
||||
|
||||
If you do use lazy list numbering, however, you should still start the
|
||||
list with the number 1. At some point in the future, Markdown may support
|
||||
starting ordered lists at an arbitrary number.
|
||||
|
||||
List markers typically start at the left margin, but may be indented by
|
||||
up to three spaces. List markers must be followed by one or more spaces
|
||||
or a tab.
|
||||
|
||||
To make lists look nice, you can wrap items with hanging indents:
|
||||
|
||||
* Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
|
||||
Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
|
||||
viverra nec, fringilla in, laoreet vitae, risus.
|
||||
* Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
|
||||
Suspendisse id sem consectetuer libero luctus adipiscing.
|
||||
|
||||
But if you want to be lazy, you don't have to:
|
||||
|
||||
* Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
|
||||
Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
|
||||
viverra nec, fringilla in, laoreet vitae, risus.
|
||||
* Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
|
||||
Suspendisse id sem consectetuer libero luctus adipiscing.
|
||||
|
||||
If list items are separated by blank lines, Markdown will wrap the
|
||||
items in `<p>` tags in the HTML output. For example, this input:
|
||||
|
||||
* Bird
|
||||
* Magic
|
||||
|
||||
will turn into:
|
||||
|
||||
<ul>
|
||||
<li>Bird</li>
|
||||
<li>Magic</li>
|
||||
</ul>
|
||||
|
||||
But this:
|
||||
|
||||
* Bird
|
||||
|
||||
* Magic
|
||||
|
||||
will turn into:
|
||||
|
||||
<ul>
|
||||
<li><p>Bird</p></li>
|
||||
<li><p>Magic</p></li>
|
||||
</ul>
|
||||
|
||||
List items may consist of multiple paragraphs. Each subsequent
|
||||
paragraph in a list item must be intended by either 4 spaces
|
||||
or one tab:
|
||||
|
||||
1. This is a list item with two paragraphs. Lorem ipsum dolor
|
||||
sit amet, consectetuer adipiscing elit. Aliquam hendrerit
|
||||
mi posuere lectus.
|
||||
|
||||
Vestibulum enim wisi, viverra nec, fringilla in, laoreet
|
||||
vitae, risus. Donec sit amet nisl. Aliquam semper ipsum
|
||||
sit amet velit.
|
||||
|
||||
2. Suspendisse id sem consectetuer libero luctus adipiscing.
|
||||
|
||||
It looks nice if you indent every line of the subsequent
|
||||
paragraphs, but here again, Markdown will allow you to be
|
||||
lazy:
|
||||
|
||||
* This is a list item with two paragraphs.
|
||||
|
||||
This is the second paragraph in the list item. You're
|
||||
only required to indent the first line. Lorem ipsum dolor
|
||||
sit amet, consectetuer adipiscing elit.
|
||||
|
||||
* Another item in the same list.
|
||||
|
||||
To put a blockquote within a list item, the blockquote's `>`
|
||||
delimiters need to be indented:
|
||||
|
||||
* A list item with a blockquote:
|
||||
|
||||
> This is a blockquote
|
||||
> inside a list item.
|
||||
|
||||
To put a code block within a list item, the code block needs
|
||||
to be indented *twice* -- 8 spaces or two tabs:
|
||||
|
||||
* A list item with a code block:
|
||||
|
||||
<code goes here>
|
||||
|
||||
|
||||
It's worth noting that it's possible to trigger an ordered list by
|
||||
accident, by writing something like this:
|
||||
|
||||
1986. What a great season.
|
||||
|
||||
In other words, a *number-period-space* sequence at the beginning of a
|
||||
line. To avoid this, you can backslash-escape the period:
|
||||
|
||||
1986\. What a great season.
|
||||
|
||||
|
||||
|
||||
<h3 id="precode">Code Blocks</h3>
|
||||
|
||||
Pre-formatted code blocks are used for writing about programming or
|
||||
markup source code. Rather than forming normal paragraphs, the lines
|
||||
of a code block are interpreted literally. Markdown wraps a code block
|
||||
in both `<pre>` and `<code>` tags.
|
||||
|
||||
To produce a code block in Markdown, simply indent every line of the
|
||||
block by at least 4 spaces or 1 tab. For example, given this input:
|
||||
|
||||
This is a normal paragraph:
|
||||
|
||||
This is a code block.
|
||||
|
||||
Markdown will generate:
|
||||
|
||||
<p>This is a normal paragraph:</p>
|
||||
|
||||
<pre><code>This is a code block.
|
||||
</code></pre>
|
||||
|
||||
One level of indentation -- 4 spaces or 1 tab -- is removed from each
|
||||
line of the code block. For example, this:
|
||||
|
||||
Here is an example of AppleScript:
|
||||
|
||||
tell application "Foo"
|
||||
beep
|
||||
end tell
|
||||
|
||||
will turn into:
|
||||
|
||||
<p>Here is an example of AppleScript:</p>
|
||||
|
||||
<pre><code>tell application "Foo"
|
||||
beep
|
||||
end tell
|
||||
</code></pre>
|
||||
|
||||
A code block continues until it reaches a line that is not indented
|
||||
(or the end of the article).
|
||||
|
||||
Within a code block, ampersands (`&`) and angle brackets (`<` and `>`)
|
||||
are automatically converted into HTML entities. This makes it very
|
||||
easy to include example HTML source code using Markdown -- just paste
|
||||
it and indent it, and Markdown will handle the hassle of encoding the
|
||||
ampersands and angle brackets. For example, this:
|
||||
|
||||
<div class="footer">
|
||||
© 2004 Foo Corporation
|
||||
</div>
|
||||
|
||||
will turn into:
|
||||
|
||||
<pre><code><div class="footer">
|
||||
&copy; 2004 Foo Corporation
|
||||
</div>
|
||||
</code></pre>
|
||||
|
||||
Regular Markdown syntax is not processed within code blocks. E.g.,
|
||||
asterisks are just literal asterisks within a code block. This means
|
||||
it's also easy to use Markdown to write about Markdown's own syntax.
|
||||
|
||||
|
||||
|
||||
<h3 id="hr">Horizontal Rules</h3>
|
||||
|
||||
You can produce a horizontal rule tag (`<hr />`) by placing three or
|
||||
more hyphens, asterisks, or underscores on a line by themselves. If you
|
||||
wish, you may use spaces between the hyphens or asterisks. Each of the
|
||||
following lines will produce a horizontal rule:
|
||||
|
||||
* * *
|
||||
|
||||
***
|
||||
|
||||
*****
|
||||
|
||||
- - -
|
||||
|
||||
---------------------------------------
|
||||
|
||||
_ _ _
|
||||
|
||||
|
||||
* * *
|
||||
|
||||
<h2 id="span">Span Elements</h2>
|
||||
|
||||
<h3 id="link">Links</h3>
|
||||
|
||||
Markdown supports two style of links: *inline* and *reference*.
|
||||
|
||||
In both styles, the link text is delimited by [square brackets].
|
||||
|
||||
To create an inline link, use a set of regular parentheses immediately
|
||||
after the link text's closing square bracket. Inside the parentheses,
|
||||
put the URL where you want the link to point, along with an *optional*
|
||||
title for the link, surrounded in quotes. For example:
|
||||
|
||||
This is [an example](http://example.com/ "Title") inline link.
|
||||
|
||||
[This link](http://example.net/) has no title attribute.
|
||||
|
||||
Will produce:
|
||||
|
||||
<p>This is <a href="http://example.com/" title="Title">
|
||||
an example</a> inline link.</p>
|
||||
|
||||
<p><a href="http://example.net/">This link</a> has no
|
||||
title attribute.</p>
|
||||
|
||||
If you're referring to a local resource on the same server, you can
|
||||
use relative paths:
|
||||
|
||||
See my [About](/about/) page for details.
|
||||
|
||||
Reference-style links use a second set of square brackets, inside
|
||||
which you place a label of your choosing to identify the link:
|
||||
|
||||
This is [an example][id] reference-style link.
|
||||
|
||||
You can optionally use a space to separate the sets of brackets:
|
||||
|
||||
This is [an example] [id] reference-style link.
|
||||
|
||||
Then, anywhere in the document, you define your link label like this,
|
||||
on a line by itself:
|
||||
|
||||
[id]: http://example.com/ "Optional Title Here"
|
||||
|
||||
That is:
|
||||
|
||||
* Square brackets containing the link identifier (optionally
|
||||
indented from the left margin using up to three spaces);
|
||||
* followed by a colon;
|
||||
* followed by one or more spaces (or tabs);
|
||||
* followed by the URL for the link;
|
||||
* optionally followed by a title attribute for the link, enclosed
|
||||
in double or single quotes.
|
||||
|
||||
The link URL may, optionally, be surrounded by angle brackets:
|
||||
|
||||
[id]: <http://example.com/> "Optional Title Here"
|
||||
|
||||
You can put the title attribute on the next line and use extra spaces
|
||||
or tabs for padding, which tends to look better with longer URLs:
|
||||
|
||||
[id]: http://example.com/longish/path/to/resource/here
|
||||
"Optional Title Here"
|
||||
|
||||
Link definitions are only used for creating links during Markdown
|
||||
processing, and are stripped from your document in the HTML output.
|
||||
|
||||
Link definition names may constist of letters, numbers, spaces, and punctuation -- but they are *not* case sensitive. E.g. these two links:
|
||||
|
||||
[link text][a]
|
||||
[link text][A]
|
||||
|
||||
are equivalent.
|
||||
|
||||
The *implicit link name* shortcut allows you to omit the name of the
|
||||
link, in which case the link text itself is used as the name.
|
||||
Just use an empty set of square brackets -- e.g., to link the word
|
||||
"Google" to the google.com web site, you could simply write:
|
||||
|
||||
[Google][]
|
||||
|
||||
And then define the link:
|
||||
|
||||
[Google]: http://google.com/
|
||||
|
||||
Because link names may contain spaces, this shortcut even works for
|
||||
multiple words in the link text:
|
||||
|
||||
Visit [Daring Fireball][] for more information.
|
||||
|
||||
And then define the link:
|
||||
|
||||
[Daring Fireball]: http://daringfireball.net/
|
||||
|
||||
Link definitions can be placed anywhere in your Markdown document. I
|
||||
tend to put them immediately after each paragraph in which they're
|
||||
used, but if you want, you can put them all at the end of your
|
||||
document, sort of like footnotes.
|
||||
|
||||
Here's an example of reference links in action:
|
||||
|
||||
I get 10 times more traffic from [Google] [1] than from
|
||||
[Yahoo] [2] or [MSN] [3].
|
||||
|
||||
[1]: http://google.com/ "Google"
|
||||
[2]: http://search.yahoo.com/ "Yahoo Search"
|
||||
[3]: http://search.msn.com/ "MSN Search"
|
||||
|
||||
Using the implicit link name shortcut, you could instead write:
|
||||
|
||||
I get 10 times more traffic from [Google][] than from
|
||||
[Yahoo][] or [MSN][].
|
||||
|
||||
[google]: http://google.com/ "Google"
|
||||
[yahoo]: http://search.yahoo.com/ "Yahoo Search"
|
||||
[msn]: http://search.msn.com/ "MSN Search"
|
||||
|
||||
Both of the above examples will produce the following HTML output:
|
||||
|
||||
<p>I get 10 times more traffic from <a href="http://google.com/"
|
||||
title="Google">Google</a> than from
|
||||
<a href="http://search.yahoo.com/" title="Yahoo Search">Yahoo</a>
|
||||
or <a href="http://search.msn.com/" title="MSN Search">MSN</a>.</p>
|
||||
|
||||
For comparison, here is the same paragraph written using
|
||||
Markdown's inline link style:
|
||||
|
||||
I get 10 times more traffic from [Google](http://google.com/ "Google")
|
||||
than from [Yahoo](http://search.yahoo.com/ "Yahoo Search") or
|
||||
[MSN](http://search.msn.com/ "MSN Search").
|
||||
|
||||
The point of reference-style links is not that they're easier to
|
||||
write. The point is that with reference-style links, your document
|
||||
source is vastly more readable. Compare the above examples: using
|
||||
reference-style links, the paragraph itself is only 81 characters
|
||||
long; with inline-style links, it's 176 characters; and as raw HTML,
|
||||
it's 234 characters. In the raw HTML, there's more markup than there
|
||||
is text.
|
||||
|
||||
With Markdown's reference-style links, a source document much more
|
||||
closely resembles the final output, as rendered in a browser. By
|
||||
allowing you to move the markup-related metadata out of the paragraph,
|
||||
you can add links without interrupting the narrative flow of your
|
||||
prose.
|
||||
|
||||
|
||||
<h3 id="em">Emphasis</h3>
|
||||
|
||||
Markdown treats asterisks (`*`) and underscores (`_`) as indicators of
|
||||
emphasis. Text wrapped with one `*` or `_` will be wrapped with an
|
||||
HTML `<em>` tag; double `*`'s or `_`'s will be wrapped with an HTML
|
||||
`<strong>` tag. E.g., this input:
|
||||
|
||||
*single asterisks*
|
||||
|
||||
_single underscores_
|
||||
|
||||
**double asterisks**
|
||||
|
||||
__double underscores__
|
||||
|
||||
will produce:
|
||||
|
||||
<em>single asterisks</em>
|
||||
|
||||
<em>single underscores</em>
|
||||
|
||||
<strong>double asterisks</strong>
|
||||
|
||||
<strong>double underscores</strong>
|
||||
|
||||
You can use whichever style you prefer; the lone restriction is that
|
||||
the same character must be used to open and close an emphasis span.
|
||||
|
||||
Emphasis can be used in the middle of a word:
|
||||
|
||||
un*fucking*believable
|
||||
|
||||
But if you surround an `*` or `_` with spaces, it'll be treated as a
|
||||
literal asterisk or underscore.
|
||||
|
||||
To produce a literal asterisk or underscore at a position where it
|
||||
would otherwise be used as an emphasis delimiter, you can backslash
|
||||
escape it:
|
||||
|
||||
\*this text is surrounded by literal asterisks\*
|
||||
|
||||
|
||||
|
||||
<h3 id="code">Code</h3>
|
||||
|
||||
To indicate a span of code, wrap it with backtick quotes (`` ` ``).
|
||||
Unlike a pre-formatted code block, a code span indicates code within a
|
||||
normal paragraph. For example:
|
||||
|
||||
Use the `printf()` function.
|
||||
|
||||
will produce:
|
||||
|
||||
<p>Use the <code>printf()</code> function.</p>
|
||||
|
||||
To include a literal backtick character within a code span, you can use
|
||||
multiple backticks as the opening and closing delimiters:
|
||||
|
||||
``There is a literal backtick (`) here.``
|
||||
|
||||
which will produce this:
|
||||
|
||||
<p><code>There is a literal backtick (`) here.</code></p>
|
||||
|
||||
The backtick delimiters surrounding a code span may include spaces --
|
||||
one after the opening, one before the closing. This allows you to place
|
||||
literal backtick characters at the beginning or end of a code span:
|
||||
|
||||
A single backtick in a code span: `` ` ``
|
||||
|
||||
A backtick-delimited string in a code span: `` `foo` ``
|
||||
|
||||
will produce:
|
||||
|
||||
<p>A single backtick in a code span: <code>`</code></p>
|
||||
|
||||
<p>A backtick-delimited string in a code span: <code>`foo`</code></p>
|
||||
|
||||
With a code span, ampersands and angle brackets are encoded as HTML
|
||||
entities automatically, which makes it easy to include example HTML
|
||||
tags. Markdown will turn this:
|
||||
|
||||
Please don't use any `<blink>` tags.
|
||||
|
||||
into:
|
||||
|
||||
<p>Please don't use any <code><blink></code> tags.</p>
|
||||
|
||||
You can write this:
|
||||
|
||||
`—` is the decimal-encoded equivalent of `—`.
|
||||
|
||||
to produce:
|
||||
|
||||
<p><code>&#8212;</code> is the decimal-encoded
|
||||
equivalent of <code>&mdash;</code>.</p>
|
||||
|
||||
|
||||
|
||||
<h3 id="img">Images</h3>
|
||||
|
||||
Admittedly, it's fairly difficult to devise a "natural" syntax for
|
||||
placing images into a plain text document format.
|
||||
|
||||
Markdown uses an image syntax that is intended to resemble the syntax
|
||||
for links, allowing for two styles: *inline* and *reference*.
|
||||
|
||||
Inline image syntax looks like this:
|
||||
|
||||
![Alt text](/path/to/img.jpg)
|
||||
|
||||
![Alt text](/path/to/img.jpg "Optional title")
|
||||
|
||||
That is:
|
||||
|
||||
* An exclamation mark: `!`;
|
||||
* followed by a set of square brackets, containing the `alt`
|
||||
attribute text for the image;
|
||||
* followed by a set of parentheses, containing the URL or path to
|
||||
the image, and an optional `title` attribute enclosed in double
|
||||
or single quotes.
|
||||
|
||||
Reference-style image syntax looks like this:
|
||||
|
||||
![Alt text][id]
|
||||
|
||||
Where "id" is the name of a defined image reference. Image references
|
||||
are defined using syntax identical to link references:
|
||||
|
||||
[id]: url/to/image "Optional title attribute"
|
||||
|
||||
As of this writing, Markdown has no syntax for specifying the
|
||||
dimensions of an image; if this is important to you, you can simply
|
||||
use regular HTML `<img>` tags.
|
||||
|
||||
|
||||
* * *
|
||||
|
||||
|
||||
<h2 id="misc">Miscellaneous</h2>
|
||||
|
||||
<h3 id="autolink">Automatic Links</h3>
|
||||
|
||||
Markdown supports a shortcut style for creating "automatic" links for URLs and email addresses: simply surround the URL or email address with angle brackets. What this means is that if you want to show the actual text of a URL or email address, and also have it be a clickable link, you can do this:
|
||||
|
||||
<http://example.com/>
|
||||
|
||||
Markdown will turn this into:
|
||||
|
||||
<a href="http://example.com/">http://example.com/</a>
|
||||
|
||||
Automatic links for email addresses work similarly, except that
|
||||
Markdown will also perform a bit of randomized decimal and hex
|
||||
entity-encoding to help obscure your address from address-harvesting
|
||||
spambots. For example, Markdown will turn this:
|
||||
|
||||
<address@example.com>
|
||||
|
||||
into something like this:
|
||||
|
||||
<a href="mailto:addre
|
||||
ss@example.co
|
||||
m">address@exa
|
||||
mple.com</a>
|
||||
|
||||
which will render in a browser as a clickable link to "address@example.com".
|
||||
|
||||
(This sort of entity-encoding trick will indeed fool many, if not
|
||||
most, address-harvesting bots, but it definitely won't fool all of
|
||||
them. It's better than nothing, but an address published in this way
|
||||
will probably eventually start receiving spam.)
|
||||
|
||||
|
||||
|
||||
<h3 id="backslash">Backslash Escapes</h3>
|
||||
|
||||
Markdown allows you to use backslash escapes to generate literal
|
||||
characters which would otherwise have special meaning in Markdown's
|
||||
formatting syntax. For example, if you wanted to surround a word with
|
||||
literal asterisks (instead of an HTML `<em>` tag), you can backslashes
|
||||
before the asterisks, like this:
|
||||
|
||||
\*literal asterisks\*
|
||||
|
||||
Markdown provides backslash escapes for the following characters:
|
||||
|
||||
\ backslash
|
||||
` backtick
|
||||
* asterisk
|
||||
_ underscore
|
||||
{} curly braces
|
||||
[] square brackets
|
||||
() parentheses
|
||||
# hash mark
|
||||
+ plus sign
|
||||
- minus sign (hyphen)
|
||||
. dot
|
||||
! exclamation mark
|
||||
|
@ -0,0 +1,9 @@
|
||||
<blockquote>
|
||||
<p>foo</p>
|
||||
|
||||
<blockquote>
|
||||
<p>bar</p>
|
||||
</blockquote>
|
||||
|
||||
<p>foo</p>
|
||||
</blockquote>
|
@ -0,0 +1,5 @@
|
||||
> foo
|
||||
>
|
||||
> > bar
|
||||
>
|
||||
> foo
|
@ -0,0 +1,148 @@
|
||||
<h2>Unordered</h2>
|
||||
|
||||
<p>Asterisks tight:</p>
|
||||
|
||||
<ul>
|
||||
<li>asterisk 1</li>
|
||||
<li>asterisk 2</li>
|
||||
<li>asterisk 3</li>
|
||||
</ul>
|
||||
|
||||
<p>Asterisks loose:</p>
|
||||
|
||||
<ul>
|
||||
<li><p>asterisk 1</p></li>
|
||||
<li><p>asterisk 2</p></li>
|
||||
<li><p>asterisk 3</p></li>
|
||||
</ul>
|
||||
|
||||
<hr />
|
||||
|
||||
<p>Pluses tight:</p>
|
||||
|
||||
<ul>
|
||||
<li>Plus 1</li>
|
||||
<li>Plus 2</li>
|
||||
<li>Plus 3</li>
|
||||
</ul>
|
||||
|
||||
<p>Pluses loose:</p>
|
||||
|
||||
<ul>
|
||||
<li><p>Plus 1</p></li>
|
||||
<li><p>Plus 2</p></li>
|
||||
<li><p>Plus 3</p></li>
|
||||
</ul>
|
||||
|
||||
<hr />
|
||||
|
||||
<p>Minuses tight:</p>
|
||||
|
||||
<ul>
|
||||
<li>Minus 1</li>
|
||||
<li>Minus 2</li>
|
||||
<li>Minus 3</li>
|
||||
</ul>
|
||||
|
||||
<p>Minuses loose:</p>
|
||||
|
||||
<ul>
|
||||
<li><p>Minus 1</p></li>
|
||||
<li><p>Minus 2</p></li>
|
||||
<li><p>Minus 3</p></li>
|
||||
</ul>
|
||||
|
||||
<h2>Ordered</h2>
|
||||
|
||||
<p>Tight:</p>
|
||||
|
||||
<ol>
|
||||
<li>First</li>
|
||||
<li>Second</li>
|
||||
<li>Third</li>
|
||||
</ol>
|
||||
|
||||
<p>and:</p>
|
||||
|
||||
<ol>
|
||||
<li>One</li>
|
||||
<li>Two</li>
|
||||
<li>Three</li>
|
||||
</ol>
|
||||
|
||||
<p>Loose using tabs:</p>
|
||||
|
||||
<ol>
|
||||
<li><p>First</p></li>
|
||||
<li><p>Second</p></li>
|
||||
<li><p>Third</p></li>
|
||||
</ol>
|
||||
|
||||
<p>and using spaces:</p>
|
||||
|
||||
<ol>
|
||||
<li><p>One</p></li>
|
||||
<li><p>Two</p></li>
|
||||
<li><p>Three</p></li>
|
||||
</ol>
|
||||
|
||||
<p>Multiple paragraphs:</p>
|
||||
|
||||
<ol>
|
||||
<li><p>Item 1, graf one.</p>
|
||||
|
||||
<p>Item 2. graf two. The quick brown fox jumped over the lazy dog's
|
||||
back.</p></li>
|
||||
<li><p>Item 2.</p></li>
|
||||
<li><p>Item 3.</p></li>
|
||||
</ol>
|
||||
|
||||
<h2>Nested</h2>
|
||||
|
||||
<ul>
|
||||
<li>Tab
|
||||
<ul>
|
||||
<li>Tab
|
||||
<ul>
|
||||
<li>Tab</li>
|
||||
</ul></li>
|
||||
</ul></li>
|
||||
</ul>
|
||||
|
||||
<p>Here's another:</p>
|
||||
|
||||
<ol>
|
||||
<li>First</li>
|
||||
<li>Second:
|
||||
<ul>
|
||||
<li>Fee</li>
|
||||
<li>Fie</li>
|
||||
<li>Foe</li>
|
||||
</ul></li>
|
||||
<li>Third</li>
|
||||
</ol>
|
||||
|
||||
<p>Same thing but with paragraphs:</p>
|
||||
|
||||
<ol>
|
||||
<li><p>First</p></li>
|
||||
<li><p>Second:</p>
|
||||
|
||||
<ul>
|
||||
<li>Fee</li>
|
||||
<li>Fie</li>
|
||||
<li>Foe</li>
|
||||
</ul></li>
|
||||
<li><p>Third</p></li>
|
||||
</ol>
|
||||
|
||||
|
||||
<p>This was an error in Markdown 1.0.1:</p>
|
||||
|
||||
<ul>
|
||||
<li><p>this</p>
|
||||
|
||||
<ul><li>sub</li></ul>
|
||||
|
||||
<p>that</p></li>
|
||||
</ul>
|
@ -0,0 +1,131 @@
|
||||
## Unordered
|
||||
|
||||
Asterisks tight:
|
||||
|
||||
* asterisk 1
|
||||
* asterisk 2
|
||||
* asterisk 3
|
||||
|
||||
|
||||
Asterisks loose:
|
||||
|
||||
* asterisk 1
|
||||
|
||||
* asterisk 2
|
||||
|
||||
* asterisk 3
|
||||
|
||||
* * *
|
||||
|
||||
Pluses tight:
|
||||
|
||||
+ Plus 1
|
||||
+ Plus 2
|
||||
+ Plus 3
|
||||
|
||||
|
||||
Pluses loose:
|
||||
|
||||
+ Plus 1
|
||||
|
||||
+ Plus 2
|
||||
|
||||
+ Plus 3
|
||||
|
||||
* * *
|
||||
|
||||
|
||||
Minuses tight:
|
||||
|
||||
- Minus 1
|
||||
- Minus 2
|
||||
- Minus 3
|
||||
|
||||
|
||||
Minuses loose:
|
||||
|
||||
- Minus 1
|
||||
|
||||
- Minus 2
|
||||
|
||||
- Minus 3
|
||||
|
||||
|
||||
## Ordered
|
||||
|
||||
Tight:
|
||||
|
||||
1. First
|
||||
2. Second
|
||||
3. Third
|
||||
|
||||
and:
|
||||
|
||||
1. One
|
||||
2. Two
|
||||
3. Three
|
||||
|
||||
|
||||
Loose using tabs:
|
||||
|
||||
1. First
|
||||
|
||||
2. Second
|
||||
|
||||
3. Third
|
||||
|
||||
and using spaces:
|
||||
|
||||
1. One
|
||||
|
||||
2. Two
|
||||
|
||||
3. Three
|
||||
|
||||
Multiple paragraphs:
|
||||
|
||||
1. Item 1, graf one.
|
||||
|
||||
Item 2. graf two. The quick brown fox jumped over the lazy dog's
|
||||
back.
|
||||
|
||||
2. Item 2.
|
||||
|
||||
3. Item 3.
|
||||
|
||||
|
||||
|
||||
## Nested
|
||||
|
||||
* Tab
|
||||
* Tab
|
||||
* Tab
|
||||
|
||||
Here's another:
|
||||
|
||||
1. First
|
||||
2. Second:
|
||||
* Fee
|
||||
* Fie
|
||||
* Foe
|
||||
3. Third
|
||||
|
||||
Same thing but with paragraphs:
|
||||
|
||||
1. First
|
||||
|
||||
2. Second:
|
||||
* Fee
|
||||
* Fie
|
||||
* Foe
|
||||
|
||||
3. Third
|
||||
|
||||
|
||||
This was an error in Markdown 1.0.1:
|
||||
|
||||
* this
|
||||
|
||||
* sub
|
||||
|
||||
that
|
@ -0,0 +1,7 @@
|
||||
<p><strong><em>This is strong and em.</em></strong></p>
|
||||
|
||||
<p>So is <strong><em>this</em></strong> word.</p>
|
||||
|
||||
<p><strong><em>This is strong and em.</em></strong></p>
|
||||
|
||||
<p>So is <strong><em>this</em></strong> word.</p>
|
@ -0,0 +1,7 @@
|
||||
***This is strong and em.***
|
||||
|
||||
So is ***this*** word.
|
||||
|
||||
___This is strong and em.___
|
||||
|
||||
So is ___this___ word.
|
25
supportlibs/pegmarkdown/MarkdownTest_1.0.3/Tests/Tabs.html
Normal file
25
supportlibs/pegmarkdown/MarkdownTest_1.0.3/Tests/Tabs.html
Normal file
@ -0,0 +1,25 @@
|
||||
<ul>
|
||||
<li><p>this is a list item
|
||||
indented with tabs</p></li>
|
||||
<li><p>this is a list item
|
||||
indented with spaces</p></li>
|
||||
</ul>
|
||||
|
||||
<p>Code:</p>
|
||||
|
||||
<pre><code>this code block is indented by one tab
|
||||
</code></pre>
|
||||
|
||||
<p>And:</p>
|
||||
|
||||
<pre><code> this code block is indented by two tabs
|
||||
</code></pre>
|
||||
|
||||
<p>And:</p>
|
||||
|
||||
<pre><code>+ this is an example list item
|
||||
indented with tabs
|
||||
|
||||
+ this is an example list item
|
||||
indented with spaces
|
||||
</code></pre>
|
21
supportlibs/pegmarkdown/MarkdownTest_1.0.3/Tests/Tabs.text
Normal file
21
supportlibs/pegmarkdown/MarkdownTest_1.0.3/Tests/Tabs.text
Normal file
@ -0,0 +1,21 @@
|
||||
+ this is a list item
|
||||
indented with tabs
|
||||
|
||||
+ this is a list item
|
||||
indented with spaces
|
||||
|
||||
Code:
|
||||
|
||||
this code block is indented by one tab
|
||||
|
||||
And:
|
||||
|
||||
this code block is indented by two tabs
|
||||
|
||||
And:
|
||||
|
||||
+ this is an example list item
|
||||
indented with tabs
|
||||
|
||||
+ this is an example list item
|
||||
indented with spaces
|
@ -0,0 +1,8 @@
|
||||
<blockquote>
|
||||
<p>A list within a blockquote:</p>
|
||||
<ul>
|
||||
<li>asterisk 1</li>
|
||||
<li>asterisk 2</li>
|
||||
<li>asterisk 3</li>
|
||||
</ul>
|
||||
</blockquote>
|
@ -0,0 +1,5 @@
|
||||
> A list within a blockquote:
|
||||
>
|
||||
> * asterisk 1
|
||||
> * asterisk 2
|
||||
> * asterisk 3
|
225
supportlibs/pegmarkdown/README.markdown
Normal file
225
supportlibs/pegmarkdown/README.markdown
Normal file
@ -0,0 +1,225 @@
|
||||
|
||||
This a forked version of peg-markdown.... only minor changes:
|
||||
|
||||
* Switch to Qt .pro make system for easy x-platform.
|
||||
|
||||
* build a library instead of exec.
|
||||
|
||||
* Add GLibFacade from multimarkdown to allow Win32 compilations.
|
||||
|
||||
* Added ifdefs for C++ linking,
|
||||
|
||||
|
||||
What is this?
|
||||
=============
|
||||
|
||||
This is an implementation of John Gruber's [markdown][] in C. It uses a
|
||||
[parsing expression grammar (PEG)][] to define the syntax. This should
|
||||
allow easy modification and extension. It currently supports output in
|
||||
HTML, LaTeX, ODF, or groff_mm formats, and adding new formats is
|
||||
relatively easy.
|
||||
|
||||
[parsing expression grammar (PEG)]: http://en.wikipedia.org/wiki/Parsing_expression_grammar
|
||||
[markdown]: http://daringfireball.net/projects/markdown/
|
||||
|
||||
It is pretty fast. A 179K text file that takes 5.7 seconds for
|
||||
Markdown.pl (v. 1.0.1) to parse takes less than 0.2 seconds for this
|
||||
markdown. It does, however, use a lot of memory (up to 4M of heap space
|
||||
while parsing the 179K file, and up to 80K for a 4K file). (Note that
|
||||
the memory leaks in earlier versions of this program have now been
|
||||
plugged.)
|
||||
|
||||
Both a library and a standalone program are provided.
|
||||
|
||||
peg-markdown is written and maintained by John MacFarlane (jgm on
|
||||
github), with significant contributions by Ryan Tomayko (rtomayko).
|
||||
It is released under both the GPL and the MIT license; see LICENSE for
|
||||
details.
|
||||
|
||||
Installing
|
||||
==========
|
||||
|
||||
On a linux or unix-based system
|
||||
-------------------------------
|
||||
|
||||
This program is written in portable ANSI C. It requires
|
||||
[glib2](http://www.gtk.org/download/index.php). Most *nix systems will have
|
||||
this installed already. The build system requires GNU make.
|
||||
|
||||
The other required dependency, [Ian Piumarta's peg/leg PEG parser
|
||||
generator](http://piumarta.com/software/peg/), is included in the source
|
||||
directory. It will be built automatically. (However, it is not as portable
|
||||
as peg-markdown itself, and seems to require gcc.)
|
||||
|
||||
To make the 'markdown' executable:
|
||||
|
||||
make
|
||||
|
||||
(Or, on some systems, `gmake`.) Then, for usage instructions:
|
||||
|
||||
./markdown --help
|
||||
|
||||
To run John Gruber's Markdown 1.0.3 test suite:
|
||||
|
||||
make test
|
||||
|
||||
The test suite will fail on one of the list tests. Here's why.
|
||||
Markdown.pl encloses "item one" in the following list in `<p>` tags:
|
||||
|
||||
1. item one
|
||||
* subitem
|
||||
* subitem
|
||||
|
||||
2. item two
|
||||
|
||||
3. item three
|
||||
|
||||
peg-markdown does not enclose "item one" in `<p>` tags unless it has a
|
||||
following blank line. This is consistent with the official markdown
|
||||
syntax description, and lets the author of the document choose whether
|
||||
`<p>` tags are desired.
|
||||
|
||||
Cross-compiling for Windows with MinGW on a linux box
|
||||
-----------------------------------------------------
|
||||
|
||||
Prerequisites:
|
||||
|
||||
* Linux system with MinGW cross compiler For Ubuntu:
|
||||
|
||||
sudo apt-get install mingw32
|
||||
|
||||
* [Windows glib-2.0 binary & development files](http://www.gtk.org/download-windows.html).
|
||||
Unzip files into cross-compiler directory tree (e.g., `/usr/i586-mingw32msvc`).
|
||||
|
||||
Steps:
|
||||
|
||||
1. Create the markdown parser using Linux-compiled `leg` from peg-0.1.4:
|
||||
|
||||
./peg-0.1.4/leg markdown_parser.leg >markdown_parser.c
|
||||
|
||||
(Note: The same thing could be accomplished by cross-compiling leg,
|
||||
executing it on Windows, and copying the resulting C file to the Linux
|
||||
cross-compiler host.)
|
||||
|
||||
2. Run the cross compiler with include flag for the Windows glib-2.0 headers:
|
||||
for example,
|
||||
|
||||
/usr/bin/i586-mingw32msvc-cc -c \
|
||||
-I/usr/i586-mingw32msvc/include/glib-2.0 \
|
||||
-I/usr/i586-mingw32msvc/lib/glib-2.0/include -Wall -O3 -ansi markdown*.c
|
||||
|
||||
3. Link against Windows glib-2.0 headers: for example,
|
||||
|
||||
/usr/bin/i586-mingw32msvc-cc markdown*.o \
|
||||
-Wl,-L/usr/i586-mingw32msvc/lib/glib,--dy,--warn-unresolved-symbols,-lglib-2.0 \
|
||||
-o markdown.exe
|
||||
|
||||
The resulting executable depends on the glib dll file, so be sure to
|
||||
load the glib binary on the Windows host.
|
||||
|
||||
Compiling with MinGW on Windows
|
||||
-------------------------------
|
||||
|
||||
These directions assume that MinGW is installed in `c:\MinGW` and glib-2.0
|
||||
is installed in the MinGW directory hierarchy (with the mingw bin directory
|
||||
in the system path).
|
||||
|
||||
Unzip peg-markdown in a temp directory. From the directory with the
|
||||
peg-markdown source, execute:
|
||||
|
||||
cd peg-0.1.4
|
||||
make PKG_CONFIG=c:/path/to/glib/bin/pkg-config.exe
|
||||
|
||||
Extensions
|
||||
==========
|
||||
|
||||
peg-markdown supports extensions to standard markdown syntax.
|
||||
These can be turned on using the command line flag `-x` or
|
||||
`--extensions`. `-x` by itself turns on all extensions. Extensions
|
||||
can also be turned on selectively, using individual command-line
|
||||
options. To see the available extensions:
|
||||
|
||||
./markdown --help-extensions
|
||||
|
||||
The `--smart` extension provides "smart quotes", dashes, and ellipses.
|
||||
|
||||
The `--notes` extension provides a footnote syntax like that of
|
||||
Pandoc or PHP Markdown Extra.
|
||||
|
||||
Using the library
|
||||
=================
|
||||
|
||||
The library exports two functions:
|
||||
|
||||
GString * markdown_to_g_string(char *text, int extensions, int output_format);
|
||||
char * markdown_to_string(char *text, int extensions, int output_format);
|
||||
|
||||
The only difference between these is that `markdown_to_g_string` returns a
|
||||
`GString` (glib's automatically resizable string), while `markdown_to_string`
|
||||
returns a regular character pointer. The memory allocated for these must be
|
||||
freed by the calling program, using `g_string_free()` or `free()`.
|
||||
|
||||
`text` is the markdown-formatted text to be converted. Note that tabs will
|
||||
be converted to spaces, using a four-space tab stop. Character encodings are
|
||||
ignored.
|
||||
|
||||
`extensions` is a bit-field specifying which syntax extensions should be used.
|
||||
If `extensions` is 0, no extensions will be used. If it is `0xFFFFFF`,
|
||||
all extensions will be used. To set extensions selectively, use the
|
||||
bitwise `&` operator and the following constants:
|
||||
|
||||
- `EXT_SMART` turns on smart quotes, dashes, and ellipses.
|
||||
- `EXT_NOTES` turns on footnote syntax. [Pandoc's footnote syntax][] is used here.
|
||||
- `EXT_FILTER_HTML` filters out raw HTML (except for styles).
|
||||
- `EXT_FILTER_STYLES` filters out styles in HTML.
|
||||
|
||||
[Pandoc's footnote syntax]: http://johnmacfarlane.net/pandoc/README.html#footnotes
|
||||
|
||||
`output_format` is either `HTML_FORMAT`, `LATEX_FORMAT`, `ODF_FORMAT`,
|
||||
or `GROFF_MM_FORMAT`.
|
||||
|
||||
To use the library, include `markdown_lib.h`. See `markdown.c` for an example.
|
||||
|
||||
Hacking
|
||||
=======
|
||||
|
||||
It should be pretty easy to modify the program to produce other formats,
|
||||
and to parse syntax extensions. A quick guide:
|
||||
|
||||
* `markdown_parser.leg` contains the grammar itself.
|
||||
|
||||
* `markdown_output.c` contains functions for printing the `Element`
|
||||
structure in various output formats.
|
||||
|
||||
* To add an output format, add the format to `markdown_formats` in
|
||||
`markdown_lib.h`. Then modify `print_element` in `markdown_output.c`,
|
||||
and add functions `print_XXXX_string`, `print_XXXX_element`, and
|
||||
`print_XXXX_element_list`. Also add an option in the main program
|
||||
that selects the new format. Don't forget to add it to the list of
|
||||
formats in the usage message.
|
||||
|
||||
* To add syntax extensions, define them in the PEG grammar
|
||||
(`markdown_parser.leg`), using existing extensions as a guide. New
|
||||
inline elements will need to be added to `Inline =`; new block
|
||||
elements will need to be added to `Block =`. (Note: the order
|
||||
of the alternatives does matter in PEG grammars.)
|
||||
|
||||
* If you need to add new types of elements, modify the `keys`
|
||||
enum in `markdown_peg.h`.
|
||||
|
||||
* By using `&{ }` rules one can selectively disable extensions
|
||||
depending on command-line options. For example,
|
||||
`&{ extension(EXT_SMART) }` succeeds only if the `EXT_SMART` bit
|
||||
of the global `syntax_extensions` is set. Add your option to
|
||||
`markdown_extensions` in `markdown_lib.h`, and add an option in
|
||||
`markdown.c` to turn on your extension.
|
||||
|
||||
* Note: Avoid using `[^abc]` character classes in the grammar, because
|
||||
they cause problems with non-ascii input. Instead, use: `( !'a' !'b'
|
||||
!'c' . )`
|
||||
|
||||
Acknowledgements
|
||||
================
|
||||
|
||||
Support for ODF output was added by Fletcher T. Penney.
|
||||
|
11
supportlibs/pegmarkdown/glib.h
Normal file
11
supportlibs/pegmarkdown/glib.h
Normal file
@ -0,0 +1,11 @@
|
||||
/*
|
||||
* glib.h
|
||||
* MultiMarkdown
|
||||
*
|
||||
* Created by Daniel Jalkut on 7/26/11.
|
||||
* Copyright 2011 __MyCompanyName__. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Just a dummy file to keep the glib-dependent sources compiling as we would hope */
|
||||
#include "GLibFacade.h"
|
183
supportlibs/pegmarkdown/markdown.c
Normal file
183
supportlibs/pegmarkdown/markdown.c
Normal file
@ -0,0 +1,183 @@
|
||||
/**********************************************************************
|
||||
|
||||
markdown.c - markdown in C using a PEG grammar.
|
||||
(c) 2008 John MacFarlane (jgm at berkeley dot edu).
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License or the MIT
|
||||
license. See LICENSE for details.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <glib.h>
|
||||
#include "markdown_peg.h"
|
||||
|
||||
static int extensions;
|
||||
|
||||
/**********************************************************************
|
||||
|
||||
The main program is just a wrapper around the library functions in
|
||||
markdown_lib.c. It parses command-line options, reads the text to
|
||||
be converted from input files or stdin, converts the text, and sends
|
||||
the output to stdout or a file. Character encodings are ignored.
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
#define VERSION "0.4.14"
|
||||
#define COPYRIGHT "Copyright (c) 2008-2009 John MacFarlane. License GPLv2+ or MIT.\n" \
|
||||
"This is free software: you are free to change and redistribute it.\n" \
|
||||
"There is NO WARRANTY, to the extent permitted by law."
|
||||
|
||||
/* print version and copyright information */
|
||||
void version(const char *progname)
|
||||
{
|
||||
printf("peg-markdown version %s\n"
|
||||
"%s\n",
|
||||
VERSION,
|
||||
COPYRIGHT);
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
|
||||
int numargs; /* number of filename arguments */
|
||||
int i;
|
||||
|
||||
GString *inputbuf;
|
||||
char *out; /* string containing processed output */
|
||||
|
||||
FILE *input;
|
||||
FILE *output;
|
||||
char curchar;
|
||||
char *progname = argv[0];
|
||||
|
||||
int output_format = HTML_FORMAT;
|
||||
|
||||
/* Code for command-line option parsing. */
|
||||
|
||||
static gboolean opt_version = FALSE;
|
||||
static gchar *opt_output = 0;
|
||||
static gchar *opt_to = 0;
|
||||
static gboolean opt_smart = FALSE;
|
||||
static gboolean opt_notes = FALSE;
|
||||
static gboolean opt_filter_html = FALSE;
|
||||
static gboolean opt_filter_styles = FALSE;
|
||||
static gboolean opt_allext = FALSE;
|
||||
|
||||
static GOptionEntry entries[] =
|
||||
{
|
||||
{ "version", 'v', 0, G_OPTION_ARG_NONE, &opt_version, "print version and exit", NULL },
|
||||
{ "output", 'o', 0, G_OPTION_ARG_STRING, &opt_output, "send output to FILE (default is stdout)", "FILE" },
|
||||
{ "to", 't', 0, G_OPTION_ARG_STRING, &opt_to, "convert to FORMAT (default is html)", "FORMAT" },
|
||||
{ "extensions", 'x', 0, G_OPTION_ARG_NONE, &opt_allext, "use all syntax extensions", NULL },
|
||||
{ "filter-html", 0, 0, G_OPTION_ARG_NONE, &opt_filter_html, "filter out raw HTML (except styles)", NULL },
|
||||
{ "filter-styles", 0, 0, G_OPTION_ARG_NONE, &opt_filter_styles, "filter out HTML styles", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
/* Options to active syntax extensions. These appear separately in --help. */
|
||||
static GOptionEntry ext_entries[] =
|
||||
{
|
||||
{ "smart", 0, 0, G_OPTION_ARG_NONE, &opt_smart, "use smart typography extension", NULL },
|
||||
{ "notes", 0, 0, G_OPTION_ARG_NONE, &opt_notes, "use notes extension", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
GError *error = NULL;
|
||||
GOptionContext *context;
|
||||
GOptionGroup *ext_group;
|
||||
|
||||
context = g_option_context_new ("[FILE...]");
|
||||
g_option_context_add_main_entries (context, entries, NULL);
|
||||
ext_group = g_option_group_new ("extensions", "Syntax extensions", "show available syntax extensions", NULL, NULL);
|
||||
g_option_group_add_entries (ext_group, ext_entries);
|
||||
g_option_context_add_group (context, ext_group);
|
||||
g_option_context_set_description (context, "Converts text in specified files (or stdin) from markdown to FORMAT.\n"
|
||||
"Available FORMATs: html, latex, groff-mm, odf");
|
||||
if (!g_option_context_parse (context, &argc, &argv, &error)) {
|
||||
g_print ("option parsing failed: %s\n", error->message);
|
||||
exit (1);
|
||||
}
|
||||
g_option_context_free(context);
|
||||
|
||||
/* Process command-line options and arguments. */
|
||||
|
||||
if (opt_version) {
|
||||
version(progname);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
extensions = 0;
|
||||
if (opt_allext)
|
||||
extensions = 0xFFFFFF; /* turn on all extensions */
|
||||
if (opt_smart)
|
||||
extensions = extensions | EXT_SMART;
|
||||
if (opt_notes)
|
||||
extensions = extensions | EXT_NOTES;
|
||||
if (opt_filter_html)
|
||||
extensions = extensions | EXT_FILTER_HTML;
|
||||
if (opt_filter_styles)
|
||||
extensions = extensions | EXT_FILTER_STYLES;
|
||||
|
||||
if (opt_to == NULL)
|
||||
output_format = HTML_FORMAT;
|
||||
else if (strcmp(opt_to, "html") == 0)
|
||||
output_format = HTML_FORMAT;
|
||||
else if (strcmp(opt_to, "latex") == 0)
|
||||
output_format = LATEX_FORMAT;
|
||||
else if (strcmp(opt_to, "groff-mm") == 0)
|
||||
output_format = GROFF_MM_FORMAT;
|
||||
else if (strcmp(opt_to, "odf") == 0)
|
||||
output_format = ODF_FORMAT;
|
||||
else {
|
||||
fprintf(stderr, "%s: Unknown output format '%s'\n", progname, opt_to);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* we allow "-" as a synonym for stdout here */
|
||||
if (opt_output == NULL || strcmp(opt_output, "-") == 0)
|
||||
output = stdout;
|
||||
else if (!(output = fopen(opt_output, "w"))) {
|
||||
perror(opt_output);
|
||||
return 1;
|
||||
}
|
||||
|
||||
inputbuf = g_string_new(""); /* string for concatenated input */
|
||||
|
||||
/* Read input from stdin or input files into inputbuf */
|
||||
|
||||
numargs = argc - 1;
|
||||
if (numargs == 0) { /* use stdin if no files specified */
|
||||
while ((curchar = fgetc(stdin)) != EOF)
|
||||
g_string_append_c(inputbuf, curchar);
|
||||
fclose(stdin);
|
||||
}
|
||||
else { /* open all the files on command line */
|
||||
for (i = 0; i < numargs; i++) {
|
||||
if ((input = fopen(argv[i+1], "r")) == NULL) {
|
||||
perror(argv[i+1]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
while ((curchar = fgetc(input)) != EOF)
|
||||
g_string_append_c(inputbuf, curchar);
|
||||
fclose(input);
|
||||
}
|
||||
}
|
||||
|
||||
out = markdown_to_string(inputbuf->str, extensions, output_format);
|
||||
fprintf(output, "%s\n", out);
|
||||
free(out);
|
||||
|
||||
g_string_free(inputbuf, true);
|
||||
|
||||
return(EXIT_SUCCESS);
|
||||
}
|
181
supportlibs/pegmarkdown/markdown_lib.c
Normal file
181
supportlibs/pegmarkdown/markdown_lib.c
Normal file
@ -0,0 +1,181 @@
|
||||
/**********************************************************************
|
||||
|
||||
markdown_lib.c - markdown in C using a PEG grammar.
|
||||
(c) 2008 John MacFarlane (jgm at berkeley dot edu).
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License or the MIT
|
||||
license. See LICENSE for details.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "markdown_peg.h"
|
||||
|
||||
#define TABSTOP 4
|
||||
|
||||
/* preformat_text - allocate and copy text buffer while
|
||||
* performing tab expansion. */
|
||||
static GString *preformat_text(char *text) {
|
||||
GString *buf;
|
||||
char next_char;
|
||||
int charstotab;
|
||||
|
||||
int len = 0;
|
||||
|
||||
buf = g_string_new("");
|
||||
|
||||
charstotab = TABSTOP;
|
||||
while ((next_char = *text++) != '\0') {
|
||||
switch (next_char) {
|
||||
case '\t':
|
||||
while (charstotab > 0)
|
||||
g_string_append_c(buf, ' '), len++, charstotab--;
|
||||
break;
|
||||
case '\n':
|
||||
g_string_append_c(buf, '\n'), len++, charstotab = TABSTOP;
|
||||
break;
|
||||
default:
|
||||
g_string_append_c(buf, next_char), len++, charstotab--;
|
||||
}
|
||||
if (charstotab == 0)
|
||||
charstotab = TABSTOP;
|
||||
}
|
||||
g_string_append(buf, "\n\n");
|
||||
return(buf);
|
||||
}
|
||||
|
||||
/* print_tree - print tree of elements, for debugging only. */
|
||||
static void print_tree(element * elt, int indent) {
|
||||
int i;
|
||||
char * key;
|
||||
while (elt != NULL) {
|
||||
for (i = 0; i < indent; i++)
|
||||
fputc(' ', stderr);
|
||||
switch (elt->key) {
|
||||
case LIST: key = "LIST"; break;
|
||||
case RAW: key = "RAW"; break;
|
||||
case SPACE: key = "SPACE"; break;
|
||||
case LINEBREAK: key = "LINEBREAK"; break;
|
||||
case ELLIPSIS: key = "ELLIPSIS"; break;
|
||||
case EMDASH: key = "EMDASH"; break;
|
||||
case ENDASH: key = "ENDASH"; break;
|
||||
case APOSTROPHE: key = "APOSTROPHE"; break;
|
||||
case SINGLEQUOTED: key = "SINGLEQUOTED"; break;
|
||||
case DOUBLEQUOTED: key = "DOUBLEQUOTED"; break;
|
||||
case STR: key = "STR"; break;
|
||||
case LINK: key = "LINK"; break;
|
||||
case IMAGE: key = "IMAGE"; break;
|
||||
case CODE: key = "CODE"; break;
|
||||
case HTML: key = "HTML"; break;
|
||||
case EMPH: key = "EMPH"; break;
|
||||
case STRONG: key = "STRONG"; break;
|
||||
case PLAIN: key = "PLAIN"; break;
|
||||
case PARA: key = "PARA"; break;
|
||||
case LISTITEM: key = "LISTITEM"; break;
|
||||
case BULLETLIST: key = "BULLETLIST"; break;
|
||||
case ORDEREDLIST: key = "ORDEREDLIST"; break;
|
||||
case H1: key = "H1"; break;
|
||||
case H2: key = "H2"; break;
|
||||
case H3: key = "H3"; break;
|
||||
case H4: key = "H4"; break;
|
||||
case H5: key = "H5"; break;
|
||||
case H6: key = "H6"; break;
|
||||
case BLOCKQUOTE: key = "BLOCKQUOTE"; break;
|
||||
case VERBATIM: key = "VERBATIM"; break;
|
||||
case HTMLBLOCK: key = "HTMLBLOCK"; break;
|
||||
case HRULE: key = "HRULE"; break;
|
||||
case REFERENCE: key = "REFERENCE"; break;
|
||||
case NOTE: key = "NOTE"; break;
|
||||
default: key = "?";
|
||||
}
|
||||
if ( elt->key == STR ) {
|
||||
fprintf(stderr, "0x%p: %s '%s'\n", (void *)elt, key, elt->contents.str);
|
||||
} else {
|
||||
fprintf(stderr, "0x%p: %s\n", (void *)elt, key);
|
||||
}
|
||||
if (elt->children)
|
||||
print_tree(elt->children, indent + 4);
|
||||
elt = elt->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* process_raw_blocks - traverses an element list, replacing any RAW elements with
|
||||
* the result of parsing them as markdown text, and recursing into the children
|
||||
* of parent elements. The result should be a tree of elements without any RAWs. */
|
||||
static element * process_raw_blocks(element *input, int extensions, element *references, element *notes) {
|
||||
element *current = NULL;
|
||||
element *last_child = NULL;
|
||||
char *contents;
|
||||
current = input;
|
||||
|
||||
while (current != NULL) {
|
||||
if (current->key == RAW) {
|
||||
/* \001 is used to indicate boundaries between nested lists when there
|
||||
* is no blank line. We split the string by \001 and parse
|
||||
* each chunk separately. */
|
||||
contents = strtok(current->contents.str, "\001");
|
||||
current->key = LIST;
|
||||
current->children = parse_markdown(contents, extensions, references, notes);
|
||||
last_child = current->children;
|
||||
while ((contents = strtok(NULL, "\001"))) {
|
||||
while (last_child->next != NULL)
|
||||
last_child = last_child->next;
|
||||
last_child->next = parse_markdown(contents, extensions, references, notes);
|
||||
}
|
||||
free(current->contents.str);
|
||||
current->contents.str = NULL;
|
||||
}
|
||||
if (current->children != NULL)
|
||||
current->children = process_raw_blocks(current->children, extensions, references, notes);
|
||||
current = current->next;
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
/* markdown_to_gstring - convert markdown text to the output format specified.
|
||||
* Returns a GString, which must be freed after use using g_string_free(). */
|
||||
GString * markdown_to_g_string(char *text, int extensions, int output_format) {
|
||||
element *result;
|
||||
element *references;
|
||||
element *notes;
|
||||
GString *formatted_text;
|
||||
GString *out;
|
||||
out = g_string_new("");
|
||||
|
||||
formatted_text = preformat_text(text);
|
||||
|
||||
references = parse_references(formatted_text->str, extensions);
|
||||
notes = parse_notes(formatted_text->str, extensions, references);
|
||||
result = parse_markdown(formatted_text->str, extensions, references, notes);
|
||||
|
||||
result = process_raw_blocks(result, extensions, references, notes);
|
||||
|
||||
g_string_free(formatted_text, TRUE);
|
||||
|
||||
print_element_list(out, result, output_format, extensions);
|
||||
|
||||
free_element_list(result);
|
||||
free_element_list(references);
|
||||
return out;
|
||||
}
|
||||
|
||||
/* markdown_to_string - convert markdown text to the output format specified.
|
||||
* Returns a null-terminated string, which must be freed after use. */
|
||||
char * markdown_to_string(char *text, int extensions, int output_format) {
|
||||
GString *out;
|
||||
char *char_out;
|
||||
out = markdown_to_g_string(text, extensions, output_format);
|
||||
char_out = out->str;
|
||||
g_string_free(out, FALSE);
|
||||
return char_out;
|
||||
}
|
||||
|
||||
/* vim:set ts=4 sw=4: */
|
38
supportlibs/pegmarkdown/markdown_lib.h
Normal file
38
supportlibs/pegmarkdown/markdown_lib.h
Normal file
@ -0,0 +1,38 @@
|
||||
#ifndef MARKDOWN_LIB_H
|
||||
#define MARKDOWN_LIB_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <glib.h>
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
enum markdown_extensions {
|
||||
EXT_SMART = 0x01,
|
||||
EXT_NOTES = 0x02,
|
||||
EXT_FILTER_HTML = 0x04,
|
||||
EXT_FILTER_STYLES = 0x08
|
||||
};
|
||||
|
||||
enum markdown_formats {
|
||||
HTML_FORMAT,
|
||||
LATEX_FORMAT,
|
||||
GROFF_MM_FORMAT,
|
||||
ODF_FORMAT
|
||||
};
|
||||
|
||||
GString * markdown_to_g_string(char *text, int extensions, int output_format);
|
||||
char * markdown_to_string(char *text, int extensions, int output_format);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/* vim: set ts=4 sw=4 : */
|
||||
#endif
|
||||
|
1121
supportlibs/pegmarkdown/markdown_output.c
Normal file
1121
supportlibs/pegmarkdown/markdown_output.c
Normal file
File diff suppressed because it is too large
Load Diff
6665
supportlibs/pegmarkdown/markdown_parser.c
Normal file
6665
supportlibs/pegmarkdown/markdown_parser.c
Normal file
File diff suppressed because it is too large
Load Diff
770
supportlibs/pegmarkdown/markdown_parser.leg
Normal file
770
supportlibs/pegmarkdown/markdown_parser.leg
Normal file
@ -0,0 +1,770 @@
|
||||
%{
|
||||
/**********************************************************************
|
||||
|
||||
markdown_parser.leg - markdown parser in C using a PEG grammar.
|
||||
(c) 2008 John MacFarlane (jgm at berkeley dot edu).
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License or the MIT
|
||||
license. See LICENSE for details.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include "markdown_peg.h"
|
||||
#include "utility_functions.h"
|
||||
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
|
||||
Definitions for leg parser generator.
|
||||
YY_INPUT is the function the parser calls to get new input.
|
||||
We take all new input from (static) charbuf.
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
|
||||
# define YYSTYPE element *
|
||||
#ifdef __DEBUG__
|
||||
# define YY_DEBUG 1
|
||||
#endif
|
||||
|
||||
#define YY_INPUT(buf, result, max_size) \
|
||||
{ \
|
||||
int yyc; \
|
||||
if (charbuf && *charbuf != '\0') { \
|
||||
yyc= *charbuf++; \
|
||||
} else { \
|
||||
yyc= EOF; \
|
||||
} \
|
||||
result= (EOF == yyc) ? 0 : (*(buf)= yyc, 1); \
|
||||
}
|
||||
|
||||
#define YY_RULE(T) T
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
|
||||
PEG grammar and parser actions for markdown syntax.
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
%}
|
||||
|
||||
Doc = BOM? a:StartList ( Block { a = cons($$, a); } )*
|
||||
{ parse_result = reverse(a); }
|
||||
|
||||
Block = BlankLine*
|
||||
( BlockQuote
|
||||
| Verbatim
|
||||
| Note
|
||||
| Reference
|
||||
| HorizontalRule
|
||||
| Heading
|
||||
| OrderedList
|
||||
| BulletList
|
||||
| HtmlBlock
|
||||
| StyleBlock
|
||||
| Para
|
||||
| Plain )
|
||||
|
||||
Para = NonindentSpace a:Inlines BlankLine+
|
||||
{ $$ = a; $$->key = PARA; }
|
||||
|
||||
Plain = a:Inlines
|
||||
{ $$ = a; $$->key = PLAIN; }
|
||||
|
||||
AtxInline = !Newline !(Sp? '#'* Sp Newline) Inline
|
||||
|
||||
AtxStart = < ( "######" | "#####" | "####" | "###" | "##" | "#" ) >
|
||||
{ $$ = mk_element(H1 + (strlen(yytext) - 1)); }
|
||||
|
||||
AtxHeading = s:AtxStart Sp? a:StartList ( AtxInline { a = cons($$, a); } )+ (Sp? '#'* Sp)? Newline
|
||||
{ $$ = mk_list(s->key, a);
|
||||
free(s); }
|
||||
|
||||
SetextHeading = SetextHeading1 | SetextHeading2
|
||||
|
||||
SetextBottom1 = '='+ Newline
|
||||
|
||||
SetextBottom2 = '-'+ Newline
|
||||
|
||||
SetextHeading1 = &(RawLine SetextBottom1)
|
||||
a:StartList ( !Endline Inline { a = cons($$, a); } )+ Sp? Newline
|
||||
SetextBottom1 { $$ = mk_list(H1, a); }
|
||||
|
||||
SetextHeading2 = &(RawLine SetextBottom2)
|
||||
a:StartList ( !Endline Inline { a = cons($$, a); } )+ Sp? Newline
|
||||
SetextBottom2 { $$ = mk_list(H2, a); }
|
||||
|
||||
Heading = SetextHeading | AtxHeading
|
||||
|
||||
BlockQuote = a:BlockQuoteRaw
|
||||
{ $$ = mk_element(BLOCKQUOTE);
|
||||
$$->children = a;
|
||||
}
|
||||
|
||||
BlockQuoteRaw = a:StartList
|
||||
(( '>' ' '? Line { a = cons($$, a); } )
|
||||
( !'>' !BlankLine Line { a = cons($$, a); } )*
|
||||
( BlankLine { a = cons(mk_str("\n"), a); } )*
|
||||
)+
|
||||
{ $$ = mk_str_from_list(a, true);
|
||||
$$->key = RAW;
|
||||
}
|
||||
|
||||
NonblankIndentedLine = !BlankLine IndentedLine
|
||||
|
||||
VerbatimChunk = a:StartList
|
||||
( BlankLine { a = cons(mk_str("\n"), a); } )*
|
||||
( NonblankIndentedLine { a = cons($$, a); } )+
|
||||
{ $$ = mk_str_from_list(a, false); }
|
||||
|
||||
Verbatim = a:StartList ( VerbatimChunk { a = cons($$, a); } )+
|
||||
{ $$ = mk_str_from_list(a, false);
|
||||
$$->key = VERBATIM; }
|
||||
|
||||
HorizontalRule = NonindentSpace
|
||||
( '*' Sp '*' Sp '*' (Sp '*')*
|
||||
| '-' Sp '-' Sp '-' (Sp '-')*
|
||||
| '_' Sp '_' Sp '_' (Sp '_')*)
|
||||
Sp Newline BlankLine+
|
||||
{ $$ = mk_element(HRULE); }
|
||||
|
||||
Bullet = !HorizontalRule NonindentSpace ('+' | '*' | '-') Spacechar+
|
||||
|
||||
BulletList = &Bullet (ListTight | ListLoose)
|
||||
{ $$->key = BULLETLIST; }
|
||||
|
||||
ListTight = a:StartList
|
||||
( ListItemTight { a = cons($$, a); } )+
|
||||
BlankLine* !(Bullet | Enumerator)
|
||||
{ $$ = mk_list(LIST, a); }
|
||||
|
||||
ListLoose = a:StartList
|
||||
( b:ListItem BlankLine*
|
||||
{ element *li;
|
||||
li = b->children;
|
||||
li->contents.str = realloc(li->contents.str, strlen(li->contents.str) + 3);
|
||||
strcat(li->contents.str, "\n\n"); /* In loose list, \n\n added to end of each element */
|
||||
a = cons(b, a);
|
||||
} )+
|
||||
{ $$ = mk_list(LIST, a); }
|
||||
|
||||
ListItem = ( Bullet | Enumerator )
|
||||
a:StartList
|
||||
ListBlock { a = cons($$, a); }
|
||||
( ListContinuationBlock { a = cons($$, a); } )*
|
||||
{ element *raw;
|
||||
raw = mk_str_from_list(a, false);
|
||||
raw->key = RAW;
|
||||
$$ = mk_element(LISTITEM);
|
||||
$$->children = raw;
|
||||
}
|
||||
|
||||
ListItemTight =
|
||||
( Bullet | Enumerator )
|
||||
a:StartList
|
||||
ListBlock { a = cons($$, a); }
|
||||
( !BlankLine
|
||||
ListContinuationBlock { a = cons($$, a); } )*
|
||||
!ListContinuationBlock
|
||||
{ element *raw;
|
||||
raw = mk_str_from_list(a, false);
|
||||
raw->key = RAW;
|
||||
$$ = mk_element(LISTITEM);
|
||||
$$->children = raw;
|
||||
}
|
||||
|
||||
ListBlock = a:StartList
|
||||
!BlankLine Line { a = cons($$, a); }
|
||||
( ListBlockLine { a = cons($$, a); } )*
|
||||
{ $$ = mk_str_from_list(a, false); }
|
||||
|
||||
ListContinuationBlock = a:StartList
|
||||
( < BlankLine* >
|
||||
{ if (strlen(yytext) == 0)
|
||||
a = cons(mk_str("\001"), a); /* block separator */
|
||||
else
|
||||
a = cons(mk_str(yytext), a); } )
|
||||
( Indent ListBlock { a = cons($$, a); } )+
|
||||
{ $$ = mk_str_from_list(a, false); }
|
||||
|
||||
Enumerator = NonindentSpace [0-9]+ '.' Spacechar+
|
||||
|
||||
OrderedList = &Enumerator (ListTight | ListLoose)
|
||||
{ $$->key = ORDEREDLIST; }
|
||||
|
||||
ListBlockLine = !BlankLine
|
||||
!( Indent? (Bullet | Enumerator) )
|
||||
!HorizontalRule
|
||||
OptionallyIndentedLine
|
||||
|
||||
# Parsers for different kinds of block-level HTML content.
|
||||
# This is repetitive due to constraints of PEG grammar.
|
||||
|
||||
HtmlBlockOpenAddress = '<' Spnl ("address" | "ADDRESS") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseAddress = '<' Spnl '/' ("address" | "ADDRESS") Spnl '>'
|
||||
HtmlBlockAddress = HtmlBlockOpenAddress (HtmlBlockAddress | !HtmlBlockCloseAddress .)* HtmlBlockCloseAddress
|
||||
|
||||
HtmlBlockOpenBlockquote = '<' Spnl ("blockquote" | "BLOCKQUOTE") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseBlockquote = '<' Spnl '/' ("blockquote" | "BLOCKQUOTE") Spnl '>'
|
||||
HtmlBlockBlockquote = HtmlBlockOpenBlockquote (HtmlBlockBlockquote | !HtmlBlockCloseBlockquote .)* HtmlBlockCloseBlockquote
|
||||
|
||||
HtmlBlockOpenCenter = '<' Spnl ("center" | "CENTER") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseCenter = '<' Spnl '/' ("center" | "CENTER") Spnl '>'
|
||||
HtmlBlockCenter = HtmlBlockOpenCenter (HtmlBlockCenter | !HtmlBlockCloseCenter .)* HtmlBlockCloseCenter
|
||||
|
||||
HtmlBlockOpenDir = '<' Spnl ("dir" | "DIR") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseDir = '<' Spnl '/' ("dir" | "DIR") Spnl '>'
|
||||
HtmlBlockDir = HtmlBlockOpenDir (HtmlBlockDir | !HtmlBlockCloseDir .)* HtmlBlockCloseDir
|
||||
|
||||
HtmlBlockOpenDiv = '<' Spnl ("div" | "DIV") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseDiv = '<' Spnl '/' ("div" | "DIV") Spnl '>'
|
||||
HtmlBlockDiv = HtmlBlockOpenDiv (HtmlBlockDiv | !HtmlBlockCloseDiv .)* HtmlBlockCloseDiv
|
||||
|
||||
HtmlBlockOpenDl = '<' Spnl ("dl" | "DL") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseDl = '<' Spnl '/' ("dl" | "DL") Spnl '>'
|
||||
HtmlBlockDl = HtmlBlockOpenDl (HtmlBlockDl | !HtmlBlockCloseDl .)* HtmlBlockCloseDl
|
||||
|
||||
HtmlBlockOpenFieldset = '<' Spnl ("fieldset" | "FIELDSET") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseFieldset = '<' Spnl '/' ("fieldset" | "FIELDSET") Spnl '>'
|
||||
HtmlBlockFieldset = HtmlBlockOpenFieldset (HtmlBlockFieldset | !HtmlBlockCloseFieldset .)* HtmlBlockCloseFieldset
|
||||
|
||||
HtmlBlockOpenForm = '<' Spnl ("form" | "FORM") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseForm = '<' Spnl '/' ("form" | "FORM") Spnl '>'
|
||||
HtmlBlockForm = HtmlBlockOpenForm (HtmlBlockForm | !HtmlBlockCloseForm .)* HtmlBlockCloseForm
|
||||
|
||||
HtmlBlockOpenH1 = '<' Spnl ("h1" | "H1") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseH1 = '<' Spnl '/' ("h1" | "H1") Spnl '>'
|
||||
HtmlBlockH1 = HtmlBlockOpenH1 (HtmlBlockH1 | !HtmlBlockCloseH1 .)* HtmlBlockCloseH1
|
||||
|
||||
HtmlBlockOpenH2 = '<' Spnl ("h2" | "H2") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseH2 = '<' Spnl '/' ("h2" | "H2") Spnl '>'
|
||||
HtmlBlockH2 = HtmlBlockOpenH2 (HtmlBlockH2 | !HtmlBlockCloseH2 .)* HtmlBlockCloseH2
|
||||
|
||||
HtmlBlockOpenH3 = '<' Spnl ("h3" | "H3") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseH3 = '<' Spnl '/' ("h3" | "H3") Spnl '>'
|
||||
HtmlBlockH3 = HtmlBlockOpenH3 (HtmlBlockH3 | !HtmlBlockCloseH3 .)* HtmlBlockCloseH3
|
||||
|
||||
HtmlBlockOpenH4 = '<' Spnl ("h4" | "H4") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseH4 = '<' Spnl '/' ("h4" | "H4") Spnl '>'
|
||||
HtmlBlockH4 = HtmlBlockOpenH4 (HtmlBlockH4 | !HtmlBlockCloseH4 .)* HtmlBlockCloseH4
|
||||
|
||||
HtmlBlockOpenH5 = '<' Spnl ("h5" | "H5") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseH5 = '<' Spnl '/' ("h5" | "H5") Spnl '>'
|
||||
HtmlBlockH5 = HtmlBlockOpenH5 (HtmlBlockH5 | !HtmlBlockCloseH5 .)* HtmlBlockCloseH5
|
||||
|
||||
HtmlBlockOpenH6 = '<' Spnl ("h6" | "H6") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseH6 = '<' Spnl '/' ("h6" | "H6") Spnl '>'
|
||||
HtmlBlockH6 = HtmlBlockOpenH6 (HtmlBlockH6 | !HtmlBlockCloseH6 .)* HtmlBlockCloseH6
|
||||
|
||||
HtmlBlockOpenMenu = '<' Spnl ("menu" | "MENU") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseMenu = '<' Spnl '/' ("menu" | "MENU") Spnl '>'
|
||||
HtmlBlockMenu = HtmlBlockOpenMenu (HtmlBlockMenu | !HtmlBlockCloseMenu .)* HtmlBlockCloseMenu
|
||||
|
||||
HtmlBlockOpenNoframes = '<' Spnl ("noframes" | "NOFRAMES") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseNoframes = '<' Spnl '/' ("noframes" | "NOFRAMES") Spnl '>'
|
||||
HtmlBlockNoframes = HtmlBlockOpenNoframes (HtmlBlockNoframes | !HtmlBlockCloseNoframes .)* HtmlBlockCloseNoframes
|
||||
|
||||
HtmlBlockOpenNoscript = '<' Spnl ("noscript" | "NOSCRIPT") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseNoscript = '<' Spnl '/' ("noscript" | "NOSCRIPT") Spnl '>'
|
||||
HtmlBlockNoscript = HtmlBlockOpenNoscript (HtmlBlockNoscript | !HtmlBlockCloseNoscript .)* HtmlBlockCloseNoscript
|
||||
|
||||
HtmlBlockOpenOl = '<' Spnl ("ol" | "OL") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseOl = '<' Spnl '/' ("ol" | "OL") Spnl '>'
|
||||
HtmlBlockOl = HtmlBlockOpenOl (HtmlBlockOl | !HtmlBlockCloseOl .)* HtmlBlockCloseOl
|
||||
|
||||
HtmlBlockOpenP = '<' Spnl ("p" | "P") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseP = '<' Spnl '/' ("p" | "P") Spnl '>'
|
||||
HtmlBlockP = HtmlBlockOpenP (HtmlBlockP | !HtmlBlockCloseP .)* HtmlBlockCloseP
|
||||
|
||||
HtmlBlockOpenPre = '<' Spnl ("pre" | "PRE") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockClosePre = '<' Spnl '/' ("pre" | "PRE") Spnl '>'
|
||||
HtmlBlockPre = HtmlBlockOpenPre (HtmlBlockPre | !HtmlBlockClosePre .)* HtmlBlockClosePre
|
||||
|
||||
HtmlBlockOpenTable = '<' Spnl ("table" | "TABLE") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseTable = '<' Spnl '/' ("table" | "TABLE") Spnl '>'
|
||||
HtmlBlockTable = HtmlBlockOpenTable (HtmlBlockTable | !HtmlBlockCloseTable .)* HtmlBlockCloseTable
|
||||
|
||||
HtmlBlockOpenUl = '<' Spnl ("ul" | "UL") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseUl = '<' Spnl '/' ("ul" | "UL") Spnl '>'
|
||||
HtmlBlockUl = HtmlBlockOpenUl (HtmlBlockUl | !HtmlBlockCloseUl .)* HtmlBlockCloseUl
|
||||
|
||||
HtmlBlockOpenDd = '<' Spnl ("dd" | "DD") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseDd = '<' Spnl '/' ("dd" | "DD") Spnl '>'
|
||||
HtmlBlockDd = HtmlBlockOpenDd (HtmlBlockDd | !HtmlBlockCloseDd .)* HtmlBlockCloseDd
|
||||
|
||||
HtmlBlockOpenDt = '<' Spnl ("dt" | "DT") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseDt = '<' Spnl '/' ("dt" | "DT") Spnl '>'
|
||||
HtmlBlockDt = HtmlBlockOpenDt (HtmlBlockDt | !HtmlBlockCloseDt .)* HtmlBlockCloseDt
|
||||
|
||||
HtmlBlockOpenFrameset = '<' Spnl ("frameset" | "FRAMESET") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseFrameset = '<' Spnl '/' ("frameset" | "FRAMESET") Spnl '>'
|
||||
HtmlBlockFrameset = HtmlBlockOpenFrameset (HtmlBlockFrameset | !HtmlBlockCloseFrameset .)* HtmlBlockCloseFrameset
|
||||
|
||||
HtmlBlockOpenLi = '<' Spnl ("li" | "LI") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseLi = '<' Spnl '/' ("li" | "LI") Spnl '>'
|
||||
HtmlBlockLi = HtmlBlockOpenLi (HtmlBlockLi | !HtmlBlockCloseLi .)* HtmlBlockCloseLi
|
||||
|
||||
HtmlBlockOpenTbody = '<' Spnl ("tbody" | "TBODY") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseTbody = '<' Spnl '/' ("tbody" | "TBODY") Spnl '>'
|
||||
HtmlBlockTbody = HtmlBlockOpenTbody (HtmlBlockTbody | !HtmlBlockCloseTbody .)* HtmlBlockCloseTbody
|
||||
|
||||
HtmlBlockOpenTd = '<' Spnl ("td" | "TD") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseTd = '<' Spnl '/' ("td" | "TD") Spnl '>'
|
||||
HtmlBlockTd = HtmlBlockOpenTd (HtmlBlockTd | !HtmlBlockCloseTd .)* HtmlBlockCloseTd
|
||||
|
||||
HtmlBlockOpenTfoot = '<' Spnl ("tfoot" | "TFOOT") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseTfoot = '<' Spnl '/' ("tfoot" | "TFOOT") Spnl '>'
|
||||
HtmlBlockTfoot = HtmlBlockOpenTfoot (HtmlBlockTfoot | !HtmlBlockCloseTfoot .)* HtmlBlockCloseTfoot
|
||||
|
||||
HtmlBlockOpenTh = '<' Spnl ("th" | "TH") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseTh = '<' Spnl '/' ("th" | "TH") Spnl '>'
|
||||
HtmlBlockTh = HtmlBlockOpenTh (HtmlBlockTh | !HtmlBlockCloseTh .)* HtmlBlockCloseTh
|
||||
|
||||
HtmlBlockOpenThead = '<' Spnl ("thead" | "THEAD") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseThead = '<' Spnl '/' ("thead" | "THEAD") Spnl '>'
|
||||
HtmlBlockThead = HtmlBlockOpenThead (HtmlBlockThead | !HtmlBlockCloseThead .)* HtmlBlockCloseThead
|
||||
|
||||
HtmlBlockOpenTr = '<' Spnl ("tr" | "TR") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseTr = '<' Spnl '/' ("tr" | "TR") Spnl '>'
|
||||
HtmlBlockTr = HtmlBlockOpenTr (HtmlBlockTr | !HtmlBlockCloseTr .)* HtmlBlockCloseTr
|
||||
|
||||
HtmlBlockOpenScript = '<' Spnl ("script" | "SCRIPT") Spnl HtmlAttribute* '>'
|
||||
HtmlBlockCloseScript = '<' Spnl '/' ("script" | "SCRIPT") Spnl '>'
|
||||
HtmlBlockScript = HtmlBlockOpenScript (!HtmlBlockCloseScript .)* HtmlBlockCloseScript
|
||||
|
||||
|
||||
HtmlBlockInTags = HtmlBlockAddress
|
||||
| HtmlBlockBlockquote
|
||||
| HtmlBlockCenter
|
||||
| HtmlBlockDir
|
||||
| HtmlBlockDiv
|
||||
| HtmlBlockDl
|
||||
| HtmlBlockFieldset
|
||||
| HtmlBlockForm
|
||||
| HtmlBlockH1
|
||||
| HtmlBlockH2
|
||||
| HtmlBlockH3
|
||||
| HtmlBlockH4
|
||||
| HtmlBlockH5
|
||||
| HtmlBlockH6
|
||||
| HtmlBlockMenu
|
||||
| HtmlBlockNoframes
|
||||
| HtmlBlockNoscript
|
||||
| HtmlBlockOl
|
||||
| HtmlBlockP
|
||||
| HtmlBlockPre
|
||||
| HtmlBlockTable
|
||||
| HtmlBlockUl
|
||||
| HtmlBlockDd
|
||||
| HtmlBlockDt
|
||||
| HtmlBlockFrameset
|
||||
| HtmlBlockLi
|
||||
| HtmlBlockTbody
|
||||
| HtmlBlockTd
|
||||
| HtmlBlockTfoot
|
||||
| HtmlBlockTh
|
||||
| HtmlBlockThead
|
||||
| HtmlBlockTr
|
||||
| HtmlBlockScript
|
||||
|
||||
HtmlBlock = < ( HtmlBlockInTags | HtmlComment | HtmlBlockSelfClosing ) >
|
||||
BlankLine+
|
||||
{ if (extension(EXT_FILTER_HTML)) {
|
||||
$$ = mk_list(LIST, NULL);
|
||||
} else {
|
||||
$$ = mk_str(yytext);
|
||||
$$->key = HTMLBLOCK;
|
||||
}
|
||||
}
|
||||
|
||||
HtmlBlockSelfClosing = '<' Spnl HtmlBlockType Spnl HtmlAttribute* '/' Spnl '>'
|
||||
|
||||
HtmlBlockType = "address" | "blockquote" | "center" | "dir" | "div" | "dl" | "fieldset" | "form" | "h1" | "h2" | "h3" |
|
||||
"h4" | "h5" | "h6" | "hr" | "isindex" | "menu" | "noframes" | "noscript" | "ol" | "p" | "pre" | "table" |
|
||||
"ul" | "dd" | "dt" | "frameset" | "li" | "tbody" | "td" | "tfoot" | "th" | "thead" | "tr" | "script" |
|
||||
"ADDRESS" | "BLOCKQUOTE" | "CENTER" | "DIR" | "DIV" | "DL" | "FIELDSET" | "FORM" | "H1" | "H2" | "H3" |
|
||||
"H4" | "H5" | "H6" | "HR" | "ISINDEX" | "MENU" | "NOFRAMES" | "NOSCRIPT" | "OL" | "P" | "PRE" | "TABLE" |
|
||||
"UL" | "DD" | "DT" | "FRAMESET" | "LI" | "TBODY" | "TD" | "TFOOT" | "TH" | "THEAD" | "TR" | "SCRIPT"
|
||||
|
||||
StyleOpen = '<' Spnl ("style" | "STYLE") Spnl HtmlAttribute* '>'
|
||||
StyleClose = '<' Spnl '/' ("style" | "STYLE") Spnl '>'
|
||||
InStyleTags = StyleOpen (!StyleClose .)* StyleClose
|
||||
StyleBlock = < InStyleTags >
|
||||
BlankLine*
|
||||
{ if (extension(EXT_FILTER_STYLES)) {
|
||||
$$ = mk_list(LIST, NULL);
|
||||
} else {
|
||||
$$ = mk_str(yytext);
|
||||
$$->key = HTMLBLOCK;
|
||||
}
|
||||
}
|
||||
|
||||
Inlines = a:StartList ( !Endline Inline { a = cons($$, a); }
|
||||
| c:Endline &Inline { a = cons(c, a); } )+ Endline?
|
||||
{ $$ = mk_list(LIST, a); }
|
||||
|
||||
Inline = Str
|
||||
| Endline
|
||||
| UlOrStarLine
|
||||
| Space
|
||||
| Strong
|
||||
| Emph
|
||||
| Image
|
||||
| Link
|
||||
| NoteReference
|
||||
| InlineNote
|
||||
| Code
|
||||
| RawHtml
|
||||
| Entity
|
||||
| EscapedChar
|
||||
| Smart
|
||||
| Symbol
|
||||
|
||||
Space = Spacechar+
|
||||
{ $$ = mk_str(" ");
|
||||
$$->key = SPACE; }
|
||||
|
||||
Str = a:StartList < NormalChar+ > { a = cons(mk_str(yytext), a); }
|
||||
( StrChunk { a = cons($$, a); } )*
|
||||
{ if (a->next == NULL) { $$ = a; } else { $$ = mk_list(LIST, a); } }
|
||||
|
||||
StrChunk = < (NormalChar | '_'+ &Alphanumeric)+ > { $$ = mk_str(yytext); } |
|
||||
AposChunk
|
||||
|
||||
AposChunk = &{ extension(EXT_SMART) } '\'' &Alphanumeric
|
||||
{ $$ = mk_element(APOSTROPHE); }
|
||||
|
||||
EscapedChar = '\\' !Newline < [-\\`|*_{}[\]()#+.!><] >
|
||||
{ $$ = mk_str(yytext); }
|
||||
|
||||
Entity = ( HexEntity | DecEntity | CharEntity )
|
||||
{ $$ = mk_str(yytext); $$->key = HTML; }
|
||||
|
||||
Endline = LineBreak | TerminalEndline | NormalEndline
|
||||
|
||||
NormalEndline = Sp Newline !BlankLine !'>' !AtxStart
|
||||
!(Line ('='+ | '-'+) Newline)
|
||||
{ $$ = mk_str("\n");
|
||||
$$->key = SPACE; }
|
||||
|
||||
TerminalEndline = Sp Newline Eof
|
||||
{ $$ = NULL; }
|
||||
|
||||
LineBreak = " " NormalEndline
|
||||
{ $$ = mk_element(LINEBREAK); }
|
||||
|
||||
Symbol = < SpecialChar >
|
||||
{ $$ = mk_str(yytext); }
|
||||
|
||||
# This keeps the parser from getting bogged down on long strings of '*' or '_',
|
||||
# or strings of '*' or '_' with space on each side:
|
||||
UlOrStarLine = (UlLine | StarLine) { $$ = mk_str(yytext); }
|
||||
StarLine = < "****" '*'* > | < Spacechar '*'+ &Spacechar >
|
||||
UlLine = < "____" '_'* > | < Spacechar '_'+ &Spacechar >
|
||||
|
||||
Emph = EmphStar | EmphUl
|
||||
|
||||
Whitespace = Spacechar | Newline
|
||||
|
||||
EmphStar = '*' !Whitespace
|
||||
a:StartList
|
||||
( !'*' b:Inline { a = cons(b, a); }
|
||||
| b:StrongStar { a = cons(b, a); }
|
||||
)+
|
||||
'*'
|
||||
{ $$ = mk_list(EMPH, a); }
|
||||
|
||||
EmphUl = '_' !Whitespace
|
||||
a:StartList
|
||||
( !'_' b:Inline { a = cons(b, a); }
|
||||
| b:StrongUl { a = cons(b, a); }
|
||||
)+
|
||||
'_'
|
||||
{ $$ = mk_list(EMPH, a); }
|
||||
|
||||
Strong = StrongStar | StrongUl
|
||||
|
||||
StrongStar = "**" !Whitespace
|
||||
a:StartList
|
||||
( !"**" b:Inline { a = cons(b, a); })+
|
||||
"**"
|
||||
{ $$ = mk_list(STRONG, a); }
|
||||
|
||||
StrongUl = "__" !Whitespace
|
||||
a:StartList
|
||||
( !"__" b:Inline { a = cons(b, a); })+
|
||||
"__"
|
||||
{ $$ = mk_list(STRONG, a); }
|
||||
|
||||
Image = '!' ( ExplicitLink | ReferenceLink )
|
||||
{ if ($$->key == LINK) {
|
||||
$$->key = IMAGE;
|
||||
} else {
|
||||
element *result;
|
||||
result = $$;
|
||||
$$->children = cons(mk_str("!"), result->children);
|
||||
} }
|
||||
|
||||
Link = ExplicitLink | ReferenceLink | AutoLink
|
||||
|
||||
ReferenceLink = ReferenceLinkDouble | ReferenceLinkSingle
|
||||
|
||||
ReferenceLinkDouble = a:Label < Spnl > !"[]" b:Label
|
||||
{ link match;
|
||||
if (find_reference(&match, b->children)) {
|
||||
$$ = mk_link(a->children, match.url, match.title);
|
||||
free(a);
|
||||
free_element_list(b);
|
||||
} else {
|
||||
element *result;
|
||||
result = mk_element(LIST);
|
||||
result->children = cons(mk_str("["), cons(a, cons(mk_str("]"), cons(mk_str(yytext),
|
||||
cons(mk_str("["), cons(b, mk_str("]")))))));
|
||||
$$ = result;
|
||||
}
|
||||
}
|
||||
|
||||
ReferenceLinkSingle = a:Label < (Spnl "[]")? >
|
||||
{ link match;
|
||||
if (find_reference(&match, a->children)) {
|
||||
$$ = mk_link(a->children, match.url, match.title);
|
||||
free(a);
|
||||
}
|
||||
else {
|
||||
element *result;
|
||||
result = mk_element(LIST);
|
||||
result->children = cons(mk_str("["), cons(a, cons(mk_str("]"), mk_str(yytext))));
|
||||
$$ = result;
|
||||
}
|
||||
}
|
||||
|
||||
ExplicitLink = l:Label '(' Sp s:Source Spnl t:Title Sp ')'
|
||||
{ $$ = mk_link(l->children, s->contents.str, t->contents.str);
|
||||
free_element(s);
|
||||
free_element(t);
|
||||
free(l); }
|
||||
|
||||
Source = ( '<' < SourceContents > '>' | < SourceContents > )
|
||||
{ $$ = mk_str(yytext); }
|
||||
|
||||
SourceContents = ( ( !'(' !')' !'>' Nonspacechar )+ | '(' SourceContents ')')*
|
||||
|
||||
Title = ( TitleSingle | TitleDouble | < "" > )
|
||||
{ $$ = mk_str(yytext); }
|
||||
|
||||
TitleSingle = '\'' < ( !( '\'' Sp ( ')' | Newline ) ) . )* > '\''
|
||||
|
||||
TitleDouble = '"' < ( !( '"' Sp ( ')' | Newline ) ) . )* > '"'
|
||||
|
||||
AutoLink = AutoLinkUrl | AutoLinkEmail
|
||||
|
||||
AutoLinkUrl = '<' < [A-Za-z]+ "://" ( !Newline !'>' . )+ > '>'
|
||||
{ $$ = mk_link(mk_str(yytext), yytext, ""); }
|
||||
|
||||
AutoLinkEmail = '<' ( "mailto:" )? < [-A-Za-z0-9+_./!%~$]+ '@' ( !Newline !'>' . )+ > '>'
|
||||
{ char *mailto = malloc(strlen(yytext) + 8);
|
||||
sprintf(mailto, "mailto:%s", yytext);
|
||||
$$ = mk_link(mk_str(yytext), mailto, "");
|
||||
free(mailto);
|
||||
}
|
||||
|
||||
Reference = NonindentSpace !"[]" l:Label ':' Spnl s:RefSrc t:RefTitle BlankLine+
|
||||
{ $$ = mk_link(l->children, s->contents.str, t->contents.str);
|
||||
free_element(s);
|
||||
free_element(t);
|
||||
free(l);
|
||||
$$->key = REFERENCE; }
|
||||
|
||||
Label = '[' ( !'^' &{ extension(EXT_NOTES) } | &. &{ !extension(EXT_NOTES) } )
|
||||
a:StartList
|
||||
( !']' Inline { a = cons($$, a); } )*
|
||||
']'
|
||||
{ $$ = mk_list(LIST, a); }
|
||||
|
||||
RefSrc = < Nonspacechar+ >
|
||||
{ $$ = mk_str(yytext);
|
||||
$$->key = HTML; }
|
||||
|
||||
RefTitle = ( RefTitleSingle | RefTitleDouble | RefTitleParens | EmptyTitle )
|
||||
{ $$ = mk_str(yytext); }
|
||||
|
||||
EmptyTitle = < "" >
|
||||
|
||||
RefTitleSingle = Spnl '\'' < ( !( '\'' Sp Newline | Newline ) . )* > '\''
|
||||
|
||||
RefTitleDouble = Spnl '"' < ( !('"' Sp Newline | Newline) . )* > '"'
|
||||
|
||||
RefTitleParens = Spnl '(' < ( !(')' Sp Newline | Newline) . )* > ')'
|
||||
|
||||
References = a:StartList
|
||||
( b:Reference { a = cons(b, a); } | SkipBlock )*
|
||||
{ references = reverse(a); }
|
||||
|
||||
Ticks1 = "`" !'`'
|
||||
Ticks2 = "``" !'`'
|
||||
Ticks3 = "```" !'`'
|
||||
Ticks4 = "````" !'`'
|
||||
Ticks5 = "`````" !'`'
|
||||
|
||||
Code = ( Ticks1 Sp < ( ( !'`' Nonspacechar )+ | !Ticks1 '`'+ | !( Sp Ticks1 ) ( Spacechar | Newline !BlankLine ) )+ > Sp Ticks1
|
||||
| Ticks2 Sp < ( ( !'`' Nonspacechar )+ | !Ticks2 '`'+ | !( Sp Ticks2 ) ( Spacechar | Newline !BlankLine ) )+ > Sp Ticks2
|
||||
| Ticks3 Sp < ( ( !'`' Nonspacechar )+ | !Ticks3 '`'+ | !( Sp Ticks3 ) ( Spacechar | Newline !BlankLine ) )+ > Sp Ticks3
|
||||
| Ticks4 Sp < ( ( !'`' Nonspacechar )+ | !Ticks4 '`'+ | !( Sp Ticks4 ) ( Spacechar | Newline !BlankLine ) )+ > Sp Ticks4
|
||||
| Ticks5 Sp < ( ( !'`' Nonspacechar )+ | !Ticks5 '`'+ | !( Sp Ticks5 ) ( Spacechar | Newline !BlankLine ) )+ > Sp Ticks5
|
||||
)
|
||||
{ $$ = mk_str(yytext); $$->key = CODE; }
|
||||
|
||||
RawHtml = < (HtmlComment | HtmlBlockScript | HtmlTag) >
|
||||
{ if (extension(EXT_FILTER_HTML)) {
|
||||
$$ = mk_list(LIST, NULL);
|
||||
} else {
|
||||
$$ = mk_str(yytext);
|
||||
$$->key = HTML;
|
||||
}
|
||||
}
|
||||
|
||||
BlankLine = Sp Newline
|
||||
|
||||
Quoted = '"' (!'"' .)* '"' | '\'' (!'\'' .)* '\''
|
||||
HtmlAttribute = (AlphanumericAscii | '-')+ Spnl ('=' Spnl (Quoted | (!'>' Nonspacechar)+))? Spnl
|
||||
HtmlComment = "<!--" (!"-->" .)* "-->"
|
||||
HtmlTag = '<' Spnl '/'? AlphanumericAscii+ Spnl HtmlAttribute* '/'? Spnl '>'
|
||||
Eof = !.
|
||||
Spacechar = ' ' | '\t'
|
||||
Nonspacechar = !Spacechar !Newline .
|
||||
Newline = '\n' | '\r' '\n'?
|
||||
Sp = Spacechar*
|
||||
Spnl = Sp (Newline Sp)?
|
||||
SpecialChar = '*' | '_' | '`' | '&' | '[' | ']' | '(' | ')' | '<' | '!' | '#' | '\\' | '\'' | '"' | ExtendedSpecialChar
|
||||
NormalChar = !( SpecialChar | Spacechar | Newline ) .
|
||||
Alphanumeric = [0-9A-Za-z] | '\200' | '\201' | '\202' | '\203' | '\204' | '\205' | '\206' | '\207' | '\210' | '\211' | '\212' | '\213' | '\214' | '\215' | '\216' | '\217' | '\220' | '\221' | '\222' | '\223' | '\224' | '\225' | '\226' | '\227' | '\230' | '\231' | '\232' | '\233' | '\234' | '\235' | '\236' | '\237' | '\240' | '\241' | '\242' | '\243' | '\244' | '\245' | '\246' | '\247' | '\250' | '\251' | '\252' | '\253' | '\254' | '\255' | '\256' | '\257' | '\260' | '\261' | '\262' | '\263' | '\264' | '\265' | '\266' | '\267' | '\270' | '\271' | '\272' | '\273' | '\274' | '\275' | '\276' | '\277' | '\300' | '\301' | '\302' | '\303' | '\304' | '\305' | '\306' | '\307' | '\310' | '\311' | '\312' | '\313' | '\314' | '\315' | '\316' | '\317' | '\320' | '\321' | '\322' | '\323' | '\324' | '\325' | '\326' | '\327' | '\330' | '\331' | '\332' | '\333' | '\334' | '\335' | '\336' | '\337' | '\340' | '\341' | '\342' | '\343' | '\344' | '\345' | '\346' | '\347' | '\350' | '\351' | '\352' | '\353' | '\354' | '\355' | '\356' | '\357' | '\360' | '\361' | '\362' | '\363' | '\364' | '\365' | '\366' | '\367' | '\370' | '\371' | '\372' | '\373' | '\374' | '\375' | '\376' | '\377'
|
||||
AlphanumericAscii = [A-Za-z0-9]
|
||||
Digit = [0-9]
|
||||
BOM = "\357\273\277"
|
||||
|
||||
HexEntity = < '&' '#' [Xx] [0-9a-fA-F]+ ';' >
|
||||
DecEntity = < '&' '#' [0-9]+ > ';' >
|
||||
CharEntity = < '&' [A-Za-z0-9]+ ';' >
|
||||
|
||||
NonindentSpace = " " | " " | " " | ""
|
||||
Indent = "\t" | " "
|
||||
IndentedLine = Indent Line
|
||||
OptionallyIndentedLine = Indent? Line
|
||||
|
||||
# StartList starts a list data structure that can be added to with cons:
|
||||
StartList = &.
|
||||
{ $$ = NULL; }
|
||||
|
||||
Line = RawLine
|
||||
{ $$ = mk_str(yytext); }
|
||||
RawLine = ( < (!'\r' !'\n' .)* Newline > | < .+ > Eof )
|
||||
|
||||
SkipBlock = HtmlBlock
|
||||
| ( !'#' !SetextBottom1 !SetextBottom2 !BlankLine RawLine )+ BlankLine*
|
||||
| BlankLine+
|
||||
| RawLine
|
||||
|
||||
# Syntax extensions
|
||||
|
||||
ExtendedSpecialChar = &{ extension(EXT_SMART) } ('.' | '-' | '\'' | '"')
|
||||
| &{ extension(EXT_NOTES) } ( '^' )
|
||||
|
||||
Smart = &{ extension(EXT_SMART) }
|
||||
( Ellipsis | Dash | SingleQuoted | DoubleQuoted | Apostrophe )
|
||||
|
||||
Apostrophe = '\''
|
||||
{ $$ = mk_element(APOSTROPHE); }
|
||||
|
||||
Ellipsis = ("..." | ". . .")
|
||||
{ $$ = mk_element(ELLIPSIS); }
|
||||
|
||||
Dash = EmDash | EnDash
|
||||
|
||||
EnDash = '-' &Digit
|
||||
{ $$ = mk_element(ENDASH); }
|
||||
|
||||
EmDash = ("---" | "--")
|
||||
{ $$ = mk_element(EMDASH); }
|
||||
|
||||
SingleQuoteStart = '\'' !(Spacechar | Newline)
|
||||
|
||||
SingleQuoteEnd = '\'' !Alphanumeric
|
||||
|
||||
SingleQuoted = SingleQuoteStart
|
||||
a:StartList
|
||||
( !SingleQuoteEnd b:Inline { a = cons(b, a); } )+
|
||||
SingleQuoteEnd
|
||||
{ $$ = mk_list(SINGLEQUOTED, a); }
|
||||
|
||||
DoubleQuoteStart = '"'
|
||||
|
||||
DoubleQuoteEnd = '"'
|
||||
|
||||
DoubleQuoted = DoubleQuoteStart
|
||||
a:StartList
|
||||
( !DoubleQuoteEnd b:Inline { a = cons(b, a); } )+
|
||||
DoubleQuoteEnd
|
||||
{ $$ = mk_list(DOUBLEQUOTED, a); }
|
||||
|
||||
NoteReference = &{ extension(EXT_NOTES) }
|
||||
ref:RawNoteReference
|
||||
{ element *match;
|
||||
if (find_note(&match, ref->contents.str)) {
|
||||
$$ = mk_element(NOTE);
|
||||
assert(match->children != NULL);
|
||||
$$->children = match->children;
|
||||
$$->contents.str = 0;
|
||||
} else {
|
||||
char *s;
|
||||
s = malloc(strlen(ref->contents.str) + 4);
|
||||
sprintf(s, "[^%s]", ref->contents.str);
|
||||
$$ = mk_str(s);
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
|
||||
RawNoteReference = "[^" < ( !Newline !']' . )+ > ']'
|
||||
{ $$ = mk_str(yytext); }
|
||||
|
||||
Note = &{ extension(EXT_NOTES) }
|
||||
NonindentSpace ref:RawNoteReference ':' Sp
|
||||
a:StartList
|
||||
( RawNoteBlock { a = cons($$, a); } )
|
||||
( &Indent RawNoteBlock { a = cons($$, a); } )*
|
||||
{ $$ = mk_list(NOTE, a);
|
||||
$$->contents.str = strdup(ref->contents.str);
|
||||
}
|
||||
|
||||
InlineNote = &{ extension(EXT_NOTES) }
|
||||
"^["
|
||||
a:StartList
|
||||
( !']' Inline { a = cons($$, a); } )+
|
||||
']'
|
||||
{ $$ = mk_list(NOTE, a);
|
||||
$$->contents.str = 0; }
|
||||
|
||||
Notes = a:StartList
|
||||
( b:Note { a = cons(b, a); } | SkipBlock )*
|
||||
{ notes = reverse(a); }
|
||||
|
||||
RawNoteBlock = a:StartList
|
||||
( !BlankLine OptionallyIndentedLine { a = cons($$, a); } )+
|
||||
( < BlankLine* > { a = cons(mk_str(yytext), a); } )
|
||||
{ $$ = mk_str_from_list(a, true);
|
||||
$$->key = RAW;
|
||||
}
|
||||
|
||||
%%
|
||||
|
||||
|
72
supportlibs/pegmarkdown/markdown_peg.h
Normal file
72
supportlibs/pegmarkdown/markdown_peg.h
Normal file
@ -0,0 +1,72 @@
|
||||
/* markdown_peg.h */
|
||||
#ifndef MARKDOWN_PEG_H
|
||||
#define MARKDOWN_PEG_H
|
||||
|
||||
#include "markdown_lib.h"
|
||||
#include <glib.h>
|
||||
|
||||
/* Information (label, URL and title) for a link. */
|
||||
struct Link {
|
||||
struct Element *label;
|
||||
char *url;
|
||||
char *title;
|
||||
};
|
||||
|
||||
typedef struct Link link;
|
||||
|
||||
/* Union for contents of an Element (string, list, or link). */
|
||||
union Contents {
|
||||
char *str;
|
||||
struct Link *link;
|
||||
};
|
||||
|
||||
/* Types of semantic values returned by parsers. */
|
||||
enum keys { LIST, /* A generic list of values. For ordered and bullet lists, see below. */
|
||||
RAW, /* Raw markdown to be processed further */
|
||||
SPACE,
|
||||
LINEBREAK,
|
||||
ELLIPSIS,
|
||||
EMDASH,
|
||||
ENDASH,
|
||||
APOSTROPHE,
|
||||
SINGLEQUOTED,
|
||||
DOUBLEQUOTED,
|
||||
STR,
|
||||
LINK,
|
||||
IMAGE,
|
||||
CODE,
|
||||
HTML,
|
||||
EMPH,
|
||||
STRONG,
|
||||
PLAIN,
|
||||
PARA,
|
||||
LISTITEM,
|
||||
BULLETLIST,
|
||||
ORDEREDLIST,
|
||||
H1, H2, H3, H4, H5, H6, /* Code assumes that these are in order. */
|
||||
BLOCKQUOTE,
|
||||
VERBATIM,
|
||||
HTMLBLOCK,
|
||||
HRULE,
|
||||
REFERENCE,
|
||||
NOTE
|
||||
};
|
||||
|
||||
/* Semantic value of a parsing action. */
|
||||
struct Element {
|
||||
int key;
|
||||
union Contents contents;
|
||||
struct Element *children;
|
||||
struct Element *next;
|
||||
};
|
||||
|
||||
typedef struct Element element;
|
||||
|
||||
element * parse_references(char *string, int extensions);
|
||||
element * parse_notes(char *string, int extensions, element *reference_list);
|
||||
element * parse_markdown(char *string, int extensions, element *reference_list, element *note_list);
|
||||
void free_element_list(element * elt);
|
||||
void free_element(element *elt);
|
||||
void print_element_list(GString *out, element *elt, int format, int exts);
|
||||
|
||||
#endif
|
181
supportlibs/pegmarkdown/odf.c
Normal file
181
supportlibs/pegmarkdown/odf.c
Normal file
@ -0,0 +1,181 @@
|
||||
/**********************************************************************
|
||||
|
||||
odf.c - Utility routines to enable ODF support in peg-multimarkdown.
|
||||
(c) 2011 Fletcher T. Penney (http://fletcherpenney.net/).
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License or the MIT
|
||||
license. See LICENSE for details.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
#include "odf.h"
|
||||
|
||||
|
||||
void print_odf_header(GString *out){
|
||||
|
||||
/* Insert required XML header */
|
||||
g_string_append_printf(out,
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" \
|
||||
"<office:document xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"\n" \
|
||||
" xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\"\n" \
|
||||
" xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\"\n" \
|
||||
" xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\"\n" \
|
||||
" xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\"\n" \
|
||||
" xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\"\n" \
|
||||
" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n" \
|
||||
" xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n" \
|
||||
" xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"\n" \
|
||||
" xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\"\n" \
|
||||
" xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\"\n" \
|
||||
" xmlns:chart=\"urn:oasis:names:tc:opendocument:xmlns:chart:1.0\"\n" \
|
||||
" xmlns:dr3d=\"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0\"\n" \
|
||||
" xmlns:math=\"http://www.w3.org/1998/Math/MathML\"\n" \
|
||||
" xmlns:form=\"urn:oasis:names:tc:opendocument:xmlns:form:1.0\"\n" \
|
||||
" xmlns:script=\"urn:oasis:names:tc:opendocument:xmlns:script:1.0\"\n" \
|
||||
" xmlns:config=\"urn:oasis:names:tc:opendocument:xmlns:config:1.0\"\n" \
|
||||
" xmlns:ooo=\"http://openoffice.org/2004/office\"\n" \
|
||||
" xmlns:ooow=\"http://openoffice.org/2004/writer\"\n" \
|
||||
" xmlns:oooc=\"http://openoffice.org/2004/calc\"\n" \
|
||||
" xmlns:dom=\"http://www.w3.org/2001/xml-events\"\n" \
|
||||
" xmlns:xforms=\"http://www.w3.org/2002/xforms\"\n" \
|
||||
" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n" \
|
||||
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" \
|
||||
" xmlns:rpt=\"http://openoffice.org/2005/report\"\n" \
|
||||
" xmlns:of=\"urn:oasis:names:tc:opendocument:xmlns:of:1.2\"\n" \
|
||||
" xmlns:xhtml=\"http://www.w3.org/1999/xhtml\"\n" \
|
||||
" xmlns:grddl=\"http://www.w3.org/2003/g/data-view#\"\n" \
|
||||
" xmlns:tableooo=\"http://openoffice.org/2009/table\"\n" \
|
||||
" xmlns:field=\"urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0\"\n" \
|
||||
" xmlns:formx=\"urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0\"\n" \
|
||||
" xmlns:css3t=\"http://www.w3.org/TR/css3-text/\"\n" \
|
||||
" office:version=\"1.2\"\n" \
|
||||
" grddl:transformation=\"http://docs.oasis-open.org/office/1.2/xslt/odf2rdf.xsl\"\n" \
|
||||
" office:mimetype=\"application/vnd.oasis.opendocument.text\">\n");
|
||||
|
||||
/* Font Declarations */
|
||||
g_string_append_printf(out, "<office:font-face-decls>\n" \
|
||||
" <style:font-face style:name=\"Courier New\" svg:font-family=\"'Courier New'\"\n" \
|
||||
" style:font-adornments=\"Regular\"\n" \
|
||||
" style:font-family-generic=\"modern\"\n" \
|
||||
" style:font-pitch=\"fixed\"/>\n" \
|
||||
"</office:font-face-decls>\n");
|
||||
|
||||
/* Append basic style information */
|
||||
g_string_append_printf(out, "<office:styles>\n" \
|
||||
"<style:style style:name=\"Standard\" style:family=\"paragraph\" style:class=\"text\">\n" \
|
||||
" <style:paragraph-properties fo:margin-top=\"0in\" fo:margin-bottom=\"0.15in\"" \
|
||||
" fo:text-align=\"justify\" style:justify-single-word=\"false\"/>\n" \
|
||||
" </style:style>\n" \
|
||||
"<style:style style:name=\"Preformatted_20_Text\" style:display-name=\"Preformatted Text\"\n" \
|
||||
" style:family=\"paragraph\"\n" \
|
||||
" style:parent-style-name=\"Standard\"\n" \
|
||||
" style:class=\"html\">\n" \
|
||||
" <style:paragraph-properties fo:margin-top=\"0in\" fo:margin-bottom=\"0in\" fo:text-align=\"start\"\n" \
|
||||
" style:justify-single-word=\"false\"/>\n" \
|
||||
" <style:text-properties style:font-name=\"Courier New\" fo:font-size=\"11pt\"\n" \
|
||||
" style:font-name-asian=\"Courier New\"\n" \
|
||||
" style:font-size-asian=\"11pt\"\n" \
|
||||
" style:font-name-complex=\"Courier New\"\n" \
|
||||
" style:font-size-complex=\"11pt\"/>\n" \
|
||||
"</style:style>\n" \
|
||||
"<style:style style:name=\"Source_20_Text\" style:display-name=\"Source Text\"\n" \
|
||||
" style:family=\"text\">\n" \
|
||||
" <style:text-properties style:font-name=\"Courier New\" style:font-name-asian=\"Courier New\"\n" \
|
||||
" style:font-name-complex=\"Courier New\"\n" \
|
||||
" fo:font-size=\"11pt\"/>\n" \
|
||||
"</style:style>\n" \
|
||||
"<style:style style:name=\"List\" style:family=\"paragraph\"\n" \
|
||||
" style:parent-style-name=\"Standard\"\n" \
|
||||
" style:class=\"list\">\n" \
|
||||
" <style:paragraph-properties fo:text-align=\"start\" style:justify-single-word=\"false\"/>\n" \
|
||||
" <style:text-properties style:font-size-asian=\"12pt\"/>\n" \
|
||||
"</style:style>\n" \
|
||||
"<style:style style:name=\"Quotations\" style:family=\"paragraph\"\n" \
|
||||
" style:parent-style-name=\"Standard\"\n" \
|
||||
" style:class=\"html\">\n" \
|
||||
" <style:paragraph-properties fo:margin-left=\"0.3937in\" fo:margin-right=\"0.3937in\" fo:margin-top=\"0in\"\n" \
|
||||
" fo:margin-bottom=\"0.1965in\"\n" \
|
||||
" fo:text-align=\"justify\"" \
|
||||
" style:justify-single-word=\"false\"" \
|
||||
" fo:text-indent=\"0in\"\n" \
|
||||
" style:auto-text-indent=\"false\"/>\n" \
|
||||
"</style:style>\n" \
|
||||
"<style:style style:name=\"Table_20_Heading\" style:display-name=\"Table Heading\"\n" \
|
||||
" style:family=\"paragraph\"\n" \
|
||||
" style:parent-style-name=\"Table_20_Contents\"\n" \
|
||||
" style:class=\"extra\">\n" \
|
||||
" <style:paragraph-properties fo:text-align=\"center\" style:justify-single-word=\"false\"\n" \
|
||||
" text:number-lines=\"false\"\n" \
|
||||
" text:line-number=\"0\"/>\n" \
|
||||
" <style:text-properties fo:font-weight=\"bold\" style:font-weight-asian=\"bold\"\n" \
|
||||
" style:font-weight-complex=\"bold\"/>\n" \
|
||||
"</style:style>\n" \
|
||||
"<style:style style:name=\"Horizontal_20_Line\" style:display-name=\"Horizontal Line\"\n" \
|
||||
" style:family=\"paragraph\"\n" \
|
||||
" style:parent-style-name=\"Standard\"\n" \
|
||||
" style:class=\"html\">\n" \
|
||||
" <style:paragraph-properties fo:margin-top=\"0in\" fo:margin-bottom=\"0.1965in\"\n" \
|
||||
" style:border-line-width-bottom=\"0.0008in 0.0138in 0.0008in\"\n" \
|
||||
" fo:padding=\"0in\"\n" \
|
||||
" fo:border-left=\"none\"\n" \
|
||||
" fo:border-right=\"none\"\n" \
|
||||
" fo:border-top=\"none\"\n" \
|
||||
" fo:border-bottom=\"0.0154in double #808080\"\n" \
|
||||
" text:number-lines=\"false\"\n" \
|
||||
" text:line-number=\"0\"\n" \
|
||||
" style:join-border=\"false\"/>\n" \
|
||||
" <style:text-properties fo:font-size=\"6pt\" style:font-size-asian=\"6pt\" style:font-size-complex=\"6pt\"/>\n" \
|
||||
"</style:style>\n" \
|
||||
"</office:styles>\n");
|
||||
|
||||
/* Automatic style information */
|
||||
g_string_append_printf(out, "<office:automatic-styles>" \
|
||||
" <style:style style:name=\"MMD-Italic\" style:family=\"text\">\n" \
|
||||
" <style:text-properties fo:font-style=\"italic\" style:font-style-asian=\"italic\"\n" \
|
||||
" style:font-style-complex=\"italic\"/>\n" \
|
||||
" </style:style>\n" \
|
||||
" <style:style style:name=\"MMD-Bold\" style:family=\"text\">\n" \
|
||||
" <style:text-properties fo:font-weight=\"bold\" style:font-weight-asian=\"bold\"\n" \
|
||||
" style:font-weight-complex=\"bold\"/>\n" \
|
||||
" </style:style>\n" \
|
||||
"<style:style style:name=\"MMD-Table\" style:family=\"paragraph\" style:parent-style-name=\"Standard\">\n" \
|
||||
" <style:paragraph-properties fo:margin-top=\"0in\" fo:margin-bottom=\"0.05in\"/>\n" \
|
||||
"</style:style>\n" \
|
||||
"<style:style style:name=\"MMD-Table-Center\" style:family=\"paragraph\" style:parent-style-name=\"MMD-Table\">\n" \
|
||||
" <style:paragraph-properties fo:text-align=\"center\" style:justify-single-word=\"false\"/>\n" \
|
||||
"</style:style>\n" \
|
||||
"<style:style style:name=\"MMD-Table-Right\" style:family=\"paragraph\" style:parent-style-name=\"MMD-Table\">\n" \
|
||||
" <style:paragraph-properties fo:text-align=\"right\" style:justify-single-word=\"false\"/>\n" \
|
||||
"</style:style>\n" \
|
||||
"<style:style style:name=\"P2\" style:family=\"paragraph\" style:parent-style-name=\"Standard\"\n" \
|
||||
" style:list-style-name=\"L2\">\n" \
|
||||
"<style:paragraph-properties fo:text-align=\"start\" style:justify-single-word=\"false\"/>\n" \
|
||||
"</style:style>\n" \
|
||||
"<style:style style:name=\"fr1\" style:family=\"graphic\" style:parent-style-name=\"Frame\">\n" \
|
||||
" <style:graphic-properties style:print-content=\"false\" style:vertical-pos=\"top\"\n" \
|
||||
" style:vertical-rel=\"baseline\"\n" \
|
||||
" fo:padding=\"0in\"\n" \
|
||||
" fo:border=\"none\"\n" \
|
||||
" style:shadow=\"none\"/>\n" \
|
||||
"</style:style>\n" \
|
||||
"</office:automatic-styles>\n" \
|
||||
"<style:style style:name=\"P1\" style:family=\"paragraph\" style:parent-style-name=\"Standard\"\n" \
|
||||
" style:list-style-name=\"L1\"/>\n" \
|
||||
"<text:list-style style:name=\"L1\">\n" \
|
||||
" <text:list-level-style-bullet />\n" \
|
||||
"</text:list-style>\n" \
|
||||
"<text:list-style style:name=\"L2\">\n" \
|
||||
" <text:list-level-style-number />\n" \
|
||||
"</text:list-style>\n");
|
||||
}
|
||||
|
||||
void print_odf_footer(GString *out) {
|
||||
g_string_append_printf(out, "</office:text>\n</office:body>\n</office:document>");
|
||||
}
|
||||
|
11
supportlibs/pegmarkdown/odf.h
Normal file
11
supportlibs/pegmarkdown/odf.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef ODF_H
|
||||
#define ODF_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <glib.h>
|
||||
|
||||
void print_odf_header(GString *out);
|
||||
void print_odf_footer(GString *out);
|
||||
#endif
|
||||
|
117
supportlibs/pegmarkdown/parsing_functions.c
Normal file
117
supportlibs/pegmarkdown/parsing_functions.c
Normal file
@ -0,0 +1,117 @@
|
||||
/* parsing_functions.c - Functions for parsing markdown and
|
||||
* freeing element lists. */
|
||||
|
||||
/* These yy_* functions come from markdown_parser.c which is
|
||||
* generated from markdown_parser.leg
|
||||
* */
|
||||
typedef int (*yyrule)();
|
||||
|
||||
extern int yyparse();
|
||||
extern int yyparsefrom(yyrule);
|
||||
extern int yy_References();
|
||||
extern int yy_Notes();
|
||||
extern int yy_Doc();
|
||||
|
||||
#include "utility_functions.h"
|
||||
#include "parsing_functions.h"
|
||||
#include "markdown_peg.h"
|
||||
|
||||
static void free_element_contents(element elt);
|
||||
|
||||
/* free_element_list - free list of elements recursively */
|
||||
void free_element_list(element * elt) {
|
||||
element * next = NULL;
|
||||
while (elt != NULL) {
|
||||
next = elt->next;
|
||||
free_element_contents(*elt);
|
||||
if (elt->children != NULL) {
|
||||
free_element_list(elt->children);
|
||||
elt->children = NULL;
|
||||
}
|
||||
free(elt);
|
||||
elt = next;
|
||||
}
|
||||
}
|
||||
|
||||
/* free_element_contents - free element contents depending on type */
|
||||
static void free_element_contents(element elt) {
|
||||
switch (elt.key) {
|
||||
case STR:
|
||||
case SPACE:
|
||||
case RAW:
|
||||
case HTMLBLOCK:
|
||||
case HTML:
|
||||
case VERBATIM:
|
||||
case CODE:
|
||||
case NOTE:
|
||||
free(elt.contents.str);
|
||||
elt.contents.str = NULL;
|
||||
break;
|
||||
case LINK:
|
||||
case IMAGE:
|
||||
case REFERENCE:
|
||||
free(elt.contents.link->url);
|
||||
elt.contents.link->url = NULL;
|
||||
free(elt.contents.link->title);
|
||||
elt.contents.link->title = NULL;
|
||||
free_element_list(elt.contents.link->label);
|
||||
free(elt.contents.link);
|
||||
elt.contents.link = NULL;
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
/* free_element - free element and contents */
|
||||
void free_element(element *elt) {
|
||||
free_element_contents(*elt);
|
||||
free(elt);
|
||||
}
|
||||
|
||||
element * parse_references(char *string, int extensions) {
|
||||
|
||||
char *oldcharbuf;
|
||||
syntax_extensions = extensions;
|
||||
|
||||
oldcharbuf = charbuf;
|
||||
charbuf = string;
|
||||
yyparsefrom(yy_References); /* first pass, just to collect references */
|
||||
charbuf = oldcharbuf;
|
||||
|
||||
return references;
|
||||
}
|
||||
|
||||
element * parse_notes(char *string, int extensions, element *reference_list) {
|
||||
|
||||
char *oldcharbuf;
|
||||
notes = NULL;
|
||||
syntax_extensions = extensions;
|
||||
|
||||
if (extension(EXT_NOTES)) {
|
||||
references = reference_list;
|
||||
oldcharbuf = charbuf;
|
||||
charbuf = string;
|
||||
yyparsefrom(yy_Notes); /* second pass for notes */
|
||||
charbuf = oldcharbuf;
|
||||
}
|
||||
|
||||
return notes;
|
||||
}
|
||||
|
||||
element * parse_markdown(char *string, int extensions, element *reference_list, element *note_list) {
|
||||
|
||||
char *oldcharbuf;
|
||||
syntax_extensions = extensions;
|
||||
references = reference_list;
|
||||
notes = note_list;
|
||||
|
||||
oldcharbuf = charbuf;
|
||||
charbuf = string;
|
||||
|
||||
yyparsefrom(yy_Doc);
|
||||
|
||||
charbuf = oldcharbuf; /* restore charbuf to original value */
|
||||
return parse_result;
|
||||
|
||||
}
|
17
supportlibs/pegmarkdown/parsing_functions.h
Normal file
17
supportlibs/pegmarkdown/parsing_functions.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef PARSING_FUNCTIONS_H
|
||||
#define PARSING_FUNCTIONS_H
|
||||
/* parsing_functions.c - Functions for parsing markdown and
|
||||
* freeing element lists. */
|
||||
|
||||
#include "markdown_peg.h"
|
||||
|
||||
/* free_element_list - free list of elements recursively */
|
||||
void free_element_list(element * elt);
|
||||
/* free_element - free element and contents */
|
||||
void free_element(element *elt);
|
||||
|
||||
element * parse_references(char *string, int extensions);
|
||||
element * parse_notes(char *string, int extensions, element *reference_list);
|
||||
element * parse_markdown(char *string, int extensions, element *reference_list, element *note_list);
|
||||
|
||||
#endif
|
65
supportlibs/pegmarkdown/peg-0.1.9/Makefile
Normal file
65
supportlibs/pegmarkdown/peg-0.1.9/Makefile
Normal file
@ -0,0 +1,65 @@
|
||||
CFLAGS = -g -Wall $(OFLAGS) $(XFLAGS)
|
||||
OFLAGS = -O3 -DNDEBUG
|
||||
#OFLAGS = -pg
|
||||
|
||||
OBJS = tree.o compile.o
|
||||
|
||||
all : peg leg
|
||||
|
||||
peg : peg.o $(OBJS)
|
||||
$(CC) $(CFLAGS) -o $@-new peg.o $(OBJS)
|
||||
mv $@-new $@
|
||||
|
||||
leg : leg.o $(OBJS)
|
||||
$(CC) $(CFLAGS) -o $@-new leg.o $(OBJS)
|
||||
mv $@-new $@
|
||||
|
||||
ROOT =
|
||||
PREFIX = /usr/local
|
||||
BINDIR = $(ROOT)$(PREFIX)/bin
|
||||
|
||||
install : $(BINDIR)/peg $(BINDIR)/leg
|
||||
|
||||
$(BINDIR)/% : %
|
||||
cp -p $< $@
|
||||
strip $@
|
||||
|
||||
uninstall : .FORCE
|
||||
rm -f $(BINDIR)/peg
|
||||
rm -f $(BINDIR)/leg
|
||||
|
||||
peg.o : peg.c peg.peg-c
|
||||
|
||||
%.peg-c : %.peg compile.c
|
||||
./peg -o $@ $<
|
||||
|
||||
leg.o : leg.c
|
||||
|
||||
leg.c : leg.leg compile.c
|
||||
./leg -o $@ $<
|
||||
|
||||
check : check-peg check-leg
|
||||
|
||||
check-peg : peg .FORCE
|
||||
./peg < peg.peg > peg.out
|
||||
diff peg.peg-c peg.out
|
||||
rm peg.out
|
||||
|
||||
check-leg : leg .FORCE
|
||||
./leg < leg.leg > leg.out
|
||||
diff leg.c leg.out
|
||||
rm leg.out
|
||||
|
||||
test examples : .FORCE
|
||||
$(SHELL) -ec '(cd examples; $(MAKE))'
|
||||
|
||||
clean : .FORCE
|
||||
rm -f *~ *.o *.peg.[cd] *.leg.[cd]
|
||||
$(SHELL) -ec '(cd examples; $(MAKE) $@)'
|
||||
|
||||
spotless : clean .FORCE
|
||||
rm -f peg
|
||||
rm -f leg
|
||||
$(SHELL) -ec '(cd examples; $(MAKE) $@)'
|
||||
|
||||
.FORCE :
|
717
supportlibs/pegmarkdown/peg-0.1.9/compile.c
Normal file
717
supportlibs/pegmarkdown/peg-0.1.9/compile.c
Normal file
@ -0,0 +1,717 @@
|
||||
/* Copyright (c) 2007, 2012 by Ian Piumarta
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the 'Software'),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, provided that the above copyright notice(s) and this
|
||||
* permission notice appear in all copies of the Software. Acknowledgement
|
||||
* of the use of this Software in supporting documentation would be
|
||||
* appreciated but is not required.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK.
|
||||
*
|
||||
* Last edited: 2012-04-29 16:09:36 by piumarta on emilia
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "version.h"
|
||||
#include "tree.h"
|
||||
|
||||
static int yyl(void)
|
||||
{
|
||||
static int prev= 0;
|
||||
return ++prev;
|
||||
}
|
||||
|
||||
static void charClassSet (unsigned char bits[], int c) { bits[c >> 3] |= (1 << (c & 7)); }
|
||||
static void charClassClear(unsigned char bits[], int c) { bits[c >> 3] &= ~(1 << (c & 7)); }
|
||||
|
||||
typedef void (*setter)(unsigned char bits[], int c);
|
||||
|
||||
static inline int oigit(int c) { return '0' <= c && c <= '7'; }
|
||||
|
||||
static int cnext(unsigned char **ccp)
|
||||
{
|
||||
unsigned char *cclass= *ccp;
|
||||
int c= *cclass++;
|
||||
if (c)
|
||||
{
|
||||
if ('\\' == c && *cclass)
|
||||
{
|
||||
switch (c= *cclass++)
|
||||
{
|
||||
case 'a': c= '\a'; break; /* bel */
|
||||
case 'b': c= '\b'; break; /* bs */
|
||||
case 'e': c= '\e'; break; /* esc */
|
||||
case 'f': c= '\f'; break; /* ff */
|
||||
case 'n': c= '\n'; break; /* nl */
|
||||
case 'r': c= '\r'; break; /* cr */
|
||||
case 't': c= '\t'; break; /* ht */
|
||||
case 'v': c= '\v'; break; /* vt */
|
||||
default:
|
||||
if (oigit(c))
|
||||
{
|
||||
c -= '0';
|
||||
if (oigit(*cclass)) c= (c << 3) + *cclass++ - '0';
|
||||
if (oigit(*cclass)) c= (c << 3) + *cclass++ - '0';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
*ccp= cclass;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
static char *makeCharClass(unsigned char *cclass)
|
||||
{
|
||||
unsigned char bits[32];
|
||||
setter set;
|
||||
int c, prev= -1;
|
||||
static char string[256];
|
||||
char *ptr;
|
||||
|
||||
if ('^' == *cclass)
|
||||
{
|
||||
memset(bits, 255, 32);
|
||||
set= charClassClear;
|
||||
++cclass;
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(bits, 0, 32);
|
||||
set= charClassSet;
|
||||
}
|
||||
|
||||
while (*cclass)
|
||||
{
|
||||
if ('-' == *cclass && cclass[1] && prev >= 0)
|
||||
{
|
||||
++cclass;
|
||||
for (c= cnext(&cclass); prev <= c; ++prev)
|
||||
set(bits, prev);
|
||||
prev= -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
c= cnext(&cclass);
|
||||
set(bits, prev= c);
|
||||
}
|
||||
}
|
||||
|
||||
ptr= string;
|
||||
for (c= 0; c < 32; ++c)
|
||||
ptr += sprintf(ptr, "\\%03o", bits[c]);
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
static void begin(void) { fprintf(output, "\n {"); }
|
||||
static void end(void) { fprintf(output, "\n }"); }
|
||||
static void label(int n) { fprintf(output, "\n l%d:;\t", n); }
|
||||
static void jump(int n) { fprintf(output, " goto l%d;", n); }
|
||||
static void save(int n) { fprintf(output, " int yypos%d= ctx->pos, yythunkpos%d= ctx->thunkpos;", n, n); }
|
||||
static void restore(int n) { fprintf(output, " ctx->pos= yypos%d; ctx->thunkpos= yythunkpos%d;", n, n); }
|
||||
|
||||
static void Node_compile_c_ko(Node *node, int ko)
|
||||
{
|
||||
assert(node);
|
||||
switch (node->type)
|
||||
{
|
||||
case Rule:
|
||||
fprintf(stderr, "\ninternal error #1 (%s)\n", node->rule.name);
|
||||
exit(1);
|
||||
break;
|
||||
|
||||
case Dot:
|
||||
fprintf(output, " if (!yymatchDot(ctx)) goto l%d;", ko);
|
||||
break;
|
||||
|
||||
case Name:
|
||||
fprintf(output, " if (!yy_%s(ctx)) goto l%d;", node->name.rule->rule.name, ko);
|
||||
if (node->name.variable)
|
||||
fprintf(output, " yyDo(ctx, yySet, %d, 0);", node->name.variable->variable.offset);
|
||||
break;
|
||||
|
||||
case Character:
|
||||
case String:
|
||||
{
|
||||
int len= strlen(node->string.value);
|
||||
if (1 == len)
|
||||
{
|
||||
if ('\'' == node->string.value[0])
|
||||
fprintf(output, " if (!yymatchChar(ctx, '\\'')) goto l%d;", ko);
|
||||
else
|
||||
fprintf(output, " if (!yymatchChar(ctx, '%s')) goto l%d;", node->string.value, ko);
|
||||
}
|
||||
else
|
||||
if (2 == len && '\\' == node->string.value[0])
|
||||
fprintf(output, " if (!yymatchChar(ctx, '%s')) goto l%d;", node->string.value, ko);
|
||||
else
|
||||
fprintf(output, " if (!yymatchString(ctx, \"%s\")) goto l%d;", node->string.value, ko);
|
||||
}
|
||||
break;
|
||||
|
||||
case Class:
|
||||
fprintf(output, " if (!yymatchClass(ctx, (unsigned char *)\"%s\")) goto l%d;", makeCharClass(node->cclass.value), ko);
|
||||
break;
|
||||
|
||||
case Action:
|
||||
fprintf(output, " yyDo(ctx, yy%s, ctx->begin, ctx->end);", node->action.name);
|
||||
break;
|
||||
|
||||
case Predicate:
|
||||
fprintf(output, " yyText(ctx, ctx->begin, ctx->end); if (!(%s)) goto l%d;", node->action.text, ko);
|
||||
break;
|
||||
|
||||
case Alternate:
|
||||
{
|
||||
int ok= yyl();
|
||||
begin();
|
||||
save(ok);
|
||||
for (node= node->alternate.first; node; node= node->alternate.next)
|
||||
if (node->alternate.next)
|
||||
{
|
||||
int next= yyl();
|
||||
Node_compile_c_ko(node, next);
|
||||
jump(ok);
|
||||
label(next);
|
||||
restore(ok);
|
||||
}
|
||||
else
|
||||
Node_compile_c_ko(node, ko);
|
||||
end();
|
||||
label(ok);
|
||||
}
|
||||
break;
|
||||
|
||||
case Sequence:
|
||||
for (node= node->sequence.first; node; node= node->sequence.next)
|
||||
Node_compile_c_ko(node, ko);
|
||||
break;
|
||||
|
||||
case PeekFor:
|
||||
{
|
||||
int ok= yyl();
|
||||
begin();
|
||||
save(ok);
|
||||
Node_compile_c_ko(node->peekFor.element, ko);
|
||||
restore(ok);
|
||||
end();
|
||||
}
|
||||
break;
|
||||
|
||||
case PeekNot:
|
||||
{
|
||||
int ok= yyl();
|
||||
begin();
|
||||
save(ok);
|
||||
Node_compile_c_ko(node->peekFor.element, ok);
|
||||
jump(ko);
|
||||
label(ok);
|
||||
restore(ok);
|
||||
end();
|
||||
}
|
||||
break;
|
||||
|
||||
case Query:
|
||||
{
|
||||
int qko= yyl(), qok= yyl();
|
||||
begin();
|
||||
save(qko);
|
||||
Node_compile_c_ko(node->query.element, qko);
|
||||
jump(qok);
|
||||
label(qko);
|
||||
restore(qko);
|
||||
end();
|
||||
label(qok);
|
||||
}
|
||||
break;
|
||||
|
||||
case Star:
|
||||
{
|
||||
int again= yyl(), out= yyl();
|
||||
label(again);
|
||||
begin();
|
||||
save(out);
|
||||
Node_compile_c_ko(node->star.element, out);
|
||||
jump(again);
|
||||
label(out);
|
||||
restore(out);
|
||||
end();
|
||||
}
|
||||
break;
|
||||
|
||||
case Plus:
|
||||
{
|
||||
int again= yyl(), out= yyl();
|
||||
Node_compile_c_ko(node->plus.element, ko);
|
||||
label(again);
|
||||
begin();
|
||||
save(out);
|
||||
Node_compile_c_ko(node->plus.element, out);
|
||||
jump(again);
|
||||
label(out);
|
||||
restore(out);
|
||||
end();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "\nNode_compile_c_ko: illegal node type %d\n", node->type);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int countVariables(Node *node)
|
||||
{
|
||||
int count= 0;
|
||||
while (node)
|
||||
{
|
||||
++count;
|
||||
node= node->variable.next;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static void defineVariables(Node *node)
|
||||
{
|
||||
int count= 0;
|
||||
while (node)
|
||||
{
|
||||
fprintf(output, "#define %s ctx->val[%d]\n", node->variable.name, --count);
|
||||
node->variable.offset= count;
|
||||
node= node->variable.next;
|
||||
}
|
||||
fprintf(output, "#define yy ctx->yy\n");
|
||||
fprintf(output, "#define yypos ctx->pos\n");
|
||||
fprintf(output, "#define yythunkpos ctx->thunkpos\n");
|
||||
}
|
||||
|
||||
static void undefineVariables(Node *node)
|
||||
{
|
||||
fprintf(output, "#undef yythunkpos\n");
|
||||
fprintf(output, "#undef yypos\n");
|
||||
fprintf(output, "#undef yy\n");
|
||||
while (node)
|
||||
{
|
||||
fprintf(output, "#undef %s\n", node->variable.name);
|
||||
node= node->variable.next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void Rule_compile_c2(Node *node)
|
||||
{
|
||||
assert(node);
|
||||
assert(Rule == node->type);
|
||||
|
||||
if (!node->rule.expression)
|
||||
fprintf(stderr, "rule '%s' used but not defined\n", node->rule.name);
|
||||
else
|
||||
{
|
||||
int ko= yyl(), safe;
|
||||
|
||||
if ((!(RuleUsed & node->rule.flags)) && (node != start))
|
||||
fprintf(stderr, "rule '%s' defined but not used\n", node->rule.name);
|
||||
|
||||
safe= ((Query == node->rule.expression->type) || (Star == node->rule.expression->type));
|
||||
|
||||
fprintf(output, "\nYY_RULE(int) yy_%s(yycontext *ctx)\n{", node->rule.name);
|
||||
if (!safe) save(0);
|
||||
if (node->rule.variables)
|
||||
fprintf(output, " yyDo(ctx, yyPush, %d, 0);", countVariables(node->rule.variables));
|
||||
fprintf(output, "\n yyprintf((stderr, \"%%s\\n\", \"%s\"));", node->rule.name);
|
||||
Node_compile_c_ko(node->rule.expression, ko);
|
||||
fprintf(output, "\n yyprintf((stderr, \" ok %%s @ %%s\\n\", \"%s\", ctx->buf+ctx->pos));", node->rule.name);
|
||||
if (node->rule.variables)
|
||||
fprintf(output, " yyDo(ctx, yyPop, %d, 0);", countVariables(node->rule.variables));
|
||||
fprintf(output, "\n return 1;");
|
||||
if (!safe)
|
||||
{
|
||||
label(ko);
|
||||
restore(0);
|
||||
fprintf(output, "\n yyprintf((stderr, \" fail %%s @ %%s\\n\", \"%s\", ctx->buf+ctx->pos));", node->rule.name);
|
||||
fprintf(output, "\n return 0;");
|
||||
}
|
||||
fprintf(output, "\n}");
|
||||
}
|
||||
|
||||
if (node->rule.next)
|
||||
Rule_compile_c2(node->rule.next);
|
||||
}
|
||||
|
||||
static char *header= "\
|
||||
#include <stdio.h>\n\
|
||||
#include <stdlib.h>\n\
|
||||
#include <string.h>\n\
|
||||
";
|
||||
|
||||
static char *preamble= "\
|
||||
#ifndef YY_LOCAL\n\
|
||||
#define YY_LOCAL(T) static T\n\
|
||||
#endif\n\
|
||||
#ifndef YY_ACTION\n\
|
||||
#define YY_ACTION(T) static T\n\
|
||||
#endif\n\
|
||||
#ifndef YY_RULE\n\
|
||||
#define YY_RULE(T) static T\n\
|
||||
#endif\n\
|
||||
#ifndef YY_PARSE\n\
|
||||
#define YY_PARSE(T) T\n\
|
||||
#endif\n\
|
||||
#ifndef YYPARSE\n\
|
||||
#define YYPARSE yyparse\n\
|
||||
#endif\n\
|
||||
#ifndef YYPARSEFROM\n\
|
||||
#define YYPARSEFROM yyparsefrom\n\
|
||||
#endif\n\
|
||||
#ifndef YY_INPUT\n\
|
||||
#define YY_INPUT(buf, result, max_size) \\\n\
|
||||
{ \\\n\
|
||||
int yyc= getchar(); \\\n\
|
||||
result= (EOF == yyc) ? 0 : (*(buf)= yyc, 1); \\\n\
|
||||
yyprintf((stderr, \"<%c>\", yyc)); \\\n\
|
||||
}\n\
|
||||
#endif\n\
|
||||
#ifndef YY_BEGIN\n\
|
||||
#define YY_BEGIN ( ctx->begin= ctx->pos, 1)\n\
|
||||
#endif\n\
|
||||
#ifndef YY_END\n\
|
||||
#define YY_END ( ctx->end= ctx->pos, 1)\n\
|
||||
#endif\n\
|
||||
#ifdef YY_DEBUG\n\
|
||||
# define yyprintf(args) fprintf args\n\
|
||||
#else\n\
|
||||
# define yyprintf(args)\n\
|
||||
#endif\n\
|
||||
#ifndef YYSTYPE\n\
|
||||
#define YYSTYPE int\n\
|
||||
#endif\n\
|
||||
\n\
|
||||
#ifndef YY_PART\n\
|
||||
\n\
|
||||
typedef struct _yycontext yycontext;\n\
|
||||
typedef void (*yyaction)(yycontext *ctx, char *yytext, int yyleng);\n\
|
||||
typedef struct _yythunk { int begin, end; yyaction action; struct _yythunk *next; } yythunk;\n\
|
||||
\n\
|
||||
struct _yycontext {\n\
|
||||
char *buf;\n\
|
||||
int buflen;\n\
|
||||
int pos;\n\
|
||||
int limit;\n\
|
||||
char *text;\n\
|
||||
int textlen;\n\
|
||||
int begin;\n\
|
||||
int end;\n\
|
||||
int textmax;\n\
|
||||
yythunk *thunks;\n\
|
||||
int thunkslen;\n\
|
||||
int thunkpos;\n\
|
||||
YYSTYPE yy;\n\
|
||||
YYSTYPE *val;\n\
|
||||
YYSTYPE *vals;\n\
|
||||
int valslen;\n\
|
||||
#ifdef YY_CTX_MEMBERS\n\
|
||||
YY_CTX_MEMBERS\n\
|
||||
#endif\n\
|
||||
};\n\
|
||||
\n\
|
||||
#ifdef YY_CTX_LOCAL\n\
|
||||
#define YY_CTX_PARAM_ yycontext *yyctx,\n\
|
||||
#define YY_CTX_PARAM yycontext *yyctx\n\
|
||||
#define YY_CTX_ARG_ yyctx,\n\
|
||||
#define YY_CTX_ARG yyctx\n\
|
||||
#else\n\
|
||||
#define YY_CTX_PARAM_\n\
|
||||
#define YY_CTX_PARAM\n\
|
||||
#define YY_CTX_ARG_\n\
|
||||
#define YY_CTX_ARG\n\
|
||||
yycontext yyctx0;\n\
|
||||
yycontext *yyctx= &yyctx0;\n\
|
||||
#endif\n\
|
||||
\n\
|
||||
YY_LOCAL(int) yyrefill(yycontext *ctx)\n\
|
||||
{\n\
|
||||
int yyn;\n\
|
||||
while (ctx->buflen - ctx->pos < 512)\n\
|
||||
{\n\
|
||||
ctx->buflen *= 2;\n\
|
||||
ctx->buf= (char *)realloc(ctx->buf, ctx->buflen);\n\
|
||||
}\n\
|
||||
YY_INPUT((ctx->buf + ctx->pos), yyn, (ctx->buflen - ctx->pos));\n\
|
||||
if (!yyn) return 0;\n\
|
||||
ctx->limit += yyn;\n\
|
||||
return 1;\n\
|
||||
}\n\
|
||||
\n\
|
||||
YY_LOCAL(int) yymatchDot(yycontext *ctx)\n\
|
||||
{\n\
|
||||
if (ctx->pos >= ctx->limit && !yyrefill(ctx)) return 0;\n\
|
||||
++ctx->pos;\n\
|
||||
return 1;\n\
|
||||
}\n\
|
||||
\n\
|
||||
YY_LOCAL(int) yymatchChar(yycontext *ctx, int c)\n\
|
||||
{\n\
|
||||
if (ctx->pos >= ctx->limit && !yyrefill(ctx)) return 0;\n\
|
||||
if ((unsigned char)ctx->buf[ctx->pos] == c)\n\
|
||||
{\n\
|
||||
++ctx->pos;\n\
|
||||
yyprintf((stderr, \" ok yymatchChar(ctx, %c) @ %s\\n\", c, ctx->buf+ctx->pos));\n\
|
||||
return 1;\n\
|
||||
}\n\
|
||||
yyprintf((stderr, \" fail yymatchChar(ctx, %c) @ %s\\n\", c, ctx->buf+ctx->pos));\n\
|
||||
return 0;\n\
|
||||
}\n\
|
||||
\n\
|
||||
YY_LOCAL(int) yymatchString(yycontext *ctx, char *s)\n\
|
||||
{\n\
|
||||
int yysav= ctx->pos;\n\
|
||||
while (*s)\n\
|
||||
{\n\
|
||||
if (ctx->pos >= ctx->limit && !yyrefill(ctx)) return 0;\n\
|
||||
if (ctx->buf[ctx->pos] != *s)\n\
|
||||
{\n\
|
||||
ctx->pos= yysav;\n\
|
||||
return 0;\n\
|
||||
}\n\
|
||||
++s;\n\
|
||||
++ctx->pos;\n\
|
||||
}\n\
|
||||
return 1;\n\
|
||||
}\n\
|
||||
\n\
|
||||
YY_LOCAL(int) yymatchClass(yycontext *ctx, unsigned char *bits)\n\
|
||||
{\n\
|
||||
int c;\n\
|
||||
if (ctx->pos >= ctx->limit && !yyrefill(ctx)) return 0;\n\
|
||||
c= (unsigned char)ctx->buf[ctx->pos];\n\
|
||||
if (bits[c >> 3] & (1 << (c & 7)))\n\
|
||||
{\n\
|
||||
++ctx->pos;\n\
|
||||
yyprintf((stderr, \" ok yymatchClass @ %s\\n\", ctx->buf+ctx->pos));\n\
|
||||
return 1;\n\
|
||||
}\n\
|
||||
yyprintf((stderr, \" fail yymatchClass @ %s\\n\", ctx->buf+ctx->pos));\n\
|
||||
return 0;\n\
|
||||
}\n\
|
||||
\n\
|
||||
YY_LOCAL(void) yyDo(yycontext *ctx, yyaction action, int begin, int end)\n\
|
||||
{\n\
|
||||
while (ctx->thunkpos >= ctx->thunkslen)\n\
|
||||
{\n\
|
||||
ctx->thunkslen *= 2;\n\
|
||||
ctx->thunks= (yythunk *)realloc(ctx->thunks, sizeof(yythunk) * ctx->thunkslen);\n\
|
||||
}\n\
|
||||
ctx->thunks[ctx->thunkpos].begin= begin;\n\
|
||||
ctx->thunks[ctx->thunkpos].end= end;\n\
|
||||
ctx->thunks[ctx->thunkpos].action= action;\n\
|
||||
++ctx->thunkpos;\n\
|
||||
}\n\
|
||||
\n\
|
||||
YY_LOCAL(int) yyText(yycontext *ctx, int begin, int end)\n\
|
||||
{\n\
|
||||
int yyleng= end - begin;\n\
|
||||
if (yyleng <= 0)\n\
|
||||
yyleng= 0;\n\
|
||||
else\n\
|
||||
{\n\
|
||||
while (ctx->textlen < (yyleng + 1))\n\
|
||||
{\n\
|
||||
ctx->textlen *= 2;\n\
|
||||
ctx->text= (char *)realloc(ctx->text, ctx->textlen);\n\
|
||||
}\n\
|
||||
memcpy(ctx->text, ctx->buf + begin, yyleng);\n\
|
||||
}\n\
|
||||
ctx->text[yyleng]= '\\0';\n\
|
||||
return yyleng;\n\
|
||||
}\n\
|
||||
\n\
|
||||
YY_LOCAL(void) yyDone(yycontext *ctx)\n\
|
||||
{\n\
|
||||
int pos;\n\
|
||||
for (pos= 0; pos < ctx->thunkpos; ++pos)\n\
|
||||
{\n\
|
||||
yythunk *thunk= &ctx->thunks[pos];\n\
|
||||
int yyleng= thunk->end ? yyText(ctx, thunk->begin, thunk->end) : thunk->begin;\n\
|
||||
yyprintf((stderr, \"DO [%d] %p %s\\n\", pos, thunk->action, ctx->text));\n\
|
||||
thunk->action(ctx, ctx->text, yyleng);\n\
|
||||
}\n\
|
||||
ctx->thunkpos= 0;\n\
|
||||
}\n\
|
||||
\n\
|
||||
YY_LOCAL(void) yyCommit(yycontext *ctx)\n\
|
||||
{\n\
|
||||
if ((ctx->limit -= ctx->pos))\n\
|
||||
{\n\
|
||||
memmove(ctx->buf, ctx->buf + ctx->pos, ctx->limit);\n\
|
||||
}\n\
|
||||
ctx->begin -= ctx->pos;\n\
|
||||
ctx->end -= ctx->pos;\n\
|
||||
ctx->pos= ctx->thunkpos= 0;\n\
|
||||
}\n\
|
||||
\n\
|
||||
YY_LOCAL(int) yyAccept(yycontext *ctx, int tp0)\n\
|
||||
{\n\
|
||||
if (tp0)\n\
|
||||
{\n\
|
||||
fprintf(stderr, \"accept denied at %d\\n\", tp0);\n\
|
||||
return 0;\n\
|
||||
}\n\
|
||||
else\n\
|
||||
{\n\
|
||||
yyDone(ctx);\n\
|
||||
yyCommit(ctx);\n\
|
||||
}\n\
|
||||
return 1;\n\
|
||||
}\n\
|
||||
\n\
|
||||
YY_LOCAL(void) yyPush(yycontext *ctx, char *text, int count) { ctx->val += count; }\n\
|
||||
YY_LOCAL(void) yyPop(yycontext *ctx, char *text, int count) { ctx->val -= count; }\n\
|
||||
YY_LOCAL(void) yySet(yycontext *ctx, char *text, int count) { ctx->val[count]= ctx->yy; }\n\
|
||||
\n\
|
||||
#endif /* YY_PART */\n\
|
||||
\n\
|
||||
#define YYACCEPT yyAccept(ctx, yythunkpos0)\n\
|
||||
\n\
|
||||
";
|
||||
|
||||
static char *footer= "\n\
|
||||
\n\
|
||||
#ifndef YY_PART\n\
|
||||
\n\
|
||||
typedef int (*yyrule)(yycontext *ctx);\n\
|
||||
\n\
|
||||
YY_PARSE(int) YYPARSEFROM(YY_CTX_PARAM_ yyrule yystart)\n\
|
||||
{\n\
|
||||
int yyok;\n\
|
||||
if (!yyctx->buflen)\n\
|
||||
{\n\
|
||||
yyctx->buflen= 1024;\n\
|
||||
yyctx->buf= (char *)malloc(yyctx->buflen);\n\
|
||||
yyctx->textlen= 1024;\n\
|
||||
yyctx->text= (char *)malloc(yyctx->textlen);\n\
|
||||
yyctx->thunkslen= 32;\n\
|
||||
yyctx->thunks= (yythunk *)malloc(sizeof(yythunk) * yyctx->thunkslen);\n\
|
||||
yyctx->valslen= 32;\n\
|
||||
yyctx->vals= (YYSTYPE *)malloc(sizeof(YYSTYPE) * yyctx->valslen);\n\
|
||||
yyctx->begin= yyctx->end= yyctx->pos= yyctx->limit= yyctx->thunkpos= 0;\n\
|
||||
}\n\
|
||||
yyctx->begin= yyctx->end= yyctx->pos;\n\
|
||||
yyctx->thunkpos= 0;\n\
|
||||
yyctx->val= yyctx->vals;\n\
|
||||
yyok= yystart(yyctx);\n\
|
||||
if (yyok) yyDone(yyctx);\n\
|
||||
yyCommit(yyctx);\n\
|
||||
return yyok;\n\
|
||||
}\n\
|
||||
\n\
|
||||
YY_PARSE(int) YYPARSE(YY_CTX_PARAM)\n\
|
||||
{\n\
|
||||
return YYPARSEFROM(YY_CTX_ARG_ yy_%s);\n\
|
||||
}\n\
|
||||
\n\
|
||||
#endif\n\
|
||||
";
|
||||
|
||||
void Rule_compile_c_header(void)
|
||||
{
|
||||
fprintf(output, "/* A recursive-descent parser generated by peg %d.%d.%d */\n", PEG_MAJOR, PEG_MINOR, PEG_LEVEL);
|
||||
fprintf(output, "\n");
|
||||
fprintf(output, "%s", header);
|
||||
fprintf(output, "#define YYRULECOUNT %d\n", ruleCount);
|
||||
}
|
||||
|
||||
int consumesInput(Node *node)
|
||||
{
|
||||
if (!node) return 0;
|
||||
|
||||
switch (node->type)
|
||||
{
|
||||
case Rule:
|
||||
{
|
||||
int result= 0;
|
||||
if (RuleReached & node->rule.flags)
|
||||
fprintf(stderr, "possible infinite left recursion in rule '%s'\n", node->rule.name);
|
||||
else
|
||||
{
|
||||
node->rule.flags |= RuleReached;
|
||||
result= consumesInput(node->rule.expression);
|
||||
node->rule.flags &= ~RuleReached;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
|
||||
case Dot: return 1;
|
||||
case Name: return consumesInput(node->name.rule);
|
||||
case Character:
|
||||
case String: return strlen(node->string.value) > 0;
|
||||
case Class: return 1;
|
||||
case Action: return 0;
|
||||
case Predicate: return 0;
|
||||
|
||||
case Alternate:
|
||||
{
|
||||
Node *n;
|
||||
for (n= node->alternate.first; n; n= n->alternate.next)
|
||||
if (!consumesInput(n))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
||||
case Sequence:
|
||||
{
|
||||
Node *n;
|
||||
for (n= node->alternate.first; n; n= n->alternate.next)
|
||||
if (consumesInput(n))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
case PeekFor: return 0;
|
||||
case PeekNot: return 0;
|
||||
case Query: return 0;
|
||||
case Star: return 0;
|
||||
case Plus: return consumesInput(node->plus.element);
|
||||
|
||||
default:
|
||||
fprintf(stderr, "\nconsumesInput: illegal node type %d\n", node->type);
|
||||
exit(1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void Rule_compile_c(Node *node)
|
||||
{
|
||||
Node *n;
|
||||
|
||||
for (n= rules; n; n= n->rule.next)
|
||||
consumesInput(n);
|
||||
|
||||
fprintf(output, "%s", preamble);
|
||||
for (n= node; n; n= n->rule.next)
|
||||
fprintf(output, "YY_RULE(int) yy_%s(yycontext *ctx); /* %d */\n", n->rule.name, n->rule.id);
|
||||
fprintf(output, "\n");
|
||||
for (n= actions; n; n= n->action.list)
|
||||
{
|
||||
fprintf(output, "YY_ACTION(void) yy%s(yycontext *ctx, char *yytext, int yyleng)\n{\n", n->action.name);
|
||||
defineVariables(n->action.rule->rule.variables);
|
||||
fprintf(output, " yyprintf((stderr, \"do yy%s\\n\"));\n", n->action.name);
|
||||
fprintf(output, " %s;\n", n->action.text);
|
||||
undefineVariables(n->action.rule->rule.variables);
|
||||
fprintf(output, "}\n");
|
||||
}
|
||||
Rule_compile_c2(node);
|
||||
fprintf(output, footer, start->rule.name);
|
||||
}
|
88
supportlibs/pegmarkdown/peg-0.1.9/examples/Makefile
Normal file
88
supportlibs/pegmarkdown/peg-0.1.9/examples/Makefile
Normal file
@ -0,0 +1,88 @@
|
||||
EXAMPLES = test rule accept wc dc dcv calc basic localctx
|
||||
|
||||
CFLAGS = -g -O3
|
||||
|
||||
DIFF = diff
|
||||
TEE = cat >
|
||||
|
||||
all : $(EXAMPLES)
|
||||
|
||||
test : .FORCE
|
||||
../peg -o test.peg.c test.peg
|
||||
$(CC) $(CFLAGS) -o test test.c
|
||||
echo 'ab.ac.ad.ae.afg.afh.afg.afh.afi.afj.' | ./$@ | $(TEE) $@.out
|
||||
$(DIFF) $@.ref $@.out
|
||||
rm -f $@.out
|
||||
@echo
|
||||
|
||||
rule : .FORCE
|
||||
../peg -o rule.peg.c rule.peg
|
||||
$(CC) $(CFLAGS) -o rule rule.c
|
||||
echo 'abcbcdabcbcdabcbcdabcbcd' | ./$@ | $(TEE) $@.out
|
||||
$(DIFF) $@.ref $@.out
|
||||
rm -f $@.out
|
||||
@echo
|
||||
|
||||
accept : .FORCE
|
||||
../peg -o accept.peg.c accept.peg
|
||||
$(CC) $(CFLAGS) -o accept accept.c
|
||||
echo 'abcbcdabcbcdabcbcdabcbcd' | ./$@ | $(TEE) $@.out
|
||||
$(DIFF) $@.ref $@.out
|
||||
rm -f $@.out
|
||||
@echo
|
||||
|
||||
wc : .FORCE
|
||||
../leg -o wc.leg.c wc.leg
|
||||
$(CC) $(CFLAGS) -o wc wc.leg.c
|
||||
cat wc.leg | ./$@ | $(TEE) $@.out
|
||||
$(DIFF) $@.ref $@.out
|
||||
rm -f $@.out
|
||||
@echo
|
||||
|
||||
dc : .FORCE
|
||||
../peg -o dc.peg.c dc.peg
|
||||
$(CC) $(CFLAGS) -o dc dc.c
|
||||
echo ' 2 *3 *(3+ 4) ' | ./dc | $(TEE) $@.out
|
||||
$(DIFF) $@.ref $@.out
|
||||
rm -f $@.out
|
||||
@echo
|
||||
|
||||
dcv : .FORCE
|
||||
../peg -o dcv.peg.c dcv.peg
|
||||
$(CC) $(CFLAGS) -o dcv dcv.c
|
||||
echo 'a = 6; b = 7; a * b' | ./dcv | $(TEE) $@.out
|
||||
$(DIFF) $@.ref $@.out
|
||||
rm -f $@.out
|
||||
@echo
|
||||
|
||||
calc : .FORCE
|
||||
../leg -o calc.leg.c calc.leg
|
||||
$(CC) $(CFLAGS) -o calc calc.leg.c
|
||||
echo 'a = 6; b = 7; a * b' | ./calc | $(TEE) $@.out
|
||||
$(DIFF) $@.ref $@.out
|
||||
rm -f $@.out
|
||||
@echo
|
||||
|
||||
basic : .FORCE
|
||||
../leg -o basic.leg.c basic.leg
|
||||
$(CC) $(CFLAGS) -o basic basic.leg.c
|
||||
( echo 'load "test"'; echo "run" ) | ./basic | $(TEE) $@.out
|
||||
$(DIFF) $@.ref $@.out
|
||||
rm -f $@.out
|
||||
@echo
|
||||
|
||||
localctx : .FORCE
|
||||
../peg -o test.peg.c test.peg
|
||||
$(CC) $(CFLAGS) -o localctx localctx.c
|
||||
echo 'ab.ac.ad.ae.afg.afh.afg.afh.afi.afj.' | ./$@ | $(TEE) $@.out
|
||||
$(DIFF) $@.ref $@.out
|
||||
rm -f $@.out
|
||||
@echo
|
||||
|
||||
clean : .FORCE
|
||||
rm -f *~ *.o *.[pl]eg.[cd] $(EXAMPLES)
|
||||
rm -rf *.dSYM
|
||||
|
||||
spotless : clean
|
||||
|
||||
.FORCE :
|
11
supportlibs/pegmarkdown/peg-0.1.9/examples/accept.c
Normal file
11
supportlibs/pegmarkdown/peg-0.1.9/examples/accept.c
Normal file
@ -0,0 +1,11 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "accept.peg.c"
|
||||
|
||||
int main()
|
||||
{
|
||||
while (yyparse());
|
||||
|
||||
return 0;
|
||||
}
|
8
supportlibs/pegmarkdown/peg-0.1.9/examples/accept.peg
Normal file
8
supportlibs/pegmarkdown/peg-0.1.9/examples/accept.peg
Normal file
@ -0,0 +1,8 @@
|
||||
start <- abcd+
|
||||
|
||||
abcd <- 'a' { printf("A %d\n", yypos); } bc { printf("ABC %d\n", yypos); } &{YYACCEPT}
|
||||
/ 'b' { printf("B %d\n", yypos); } cd { printf("BCD %d\n", yypos); } &{YYACCEPT}
|
||||
|
||||
bc <- 'b' { printf("B %d\n", yypos); } 'c' { printf("C %d\n", yypos); }
|
||||
|
||||
cd <- 'c' { printf("C %d\n", yypos); } 'd' { printf("D %d\n", yypos); }
|
32
supportlibs/pegmarkdown/peg-0.1.9/examples/accept.ref
Normal file
32
supportlibs/pegmarkdown/peg-0.1.9/examples/accept.ref
Normal file
@ -0,0 +1,32 @@
|
||||
A 3
|
||||
B 3
|
||||
C 3
|
||||
ABC 3
|
||||
B 3
|
||||
C 3
|
||||
D 3
|
||||
BCD 3
|
||||
A 3
|
||||
B 3
|
||||
C 3
|
||||
ABC 3
|
||||
B 3
|
||||
C 3
|
||||
D 3
|
||||
BCD 3
|
||||
A 3
|
||||
B 3
|
||||
C 3
|
||||
ABC 3
|
||||
B 3
|
||||
C 3
|
||||
D 3
|
||||
BCD 3
|
||||
A 3
|
||||
B 3
|
||||
C 3
|
||||
ABC 3
|
||||
B 3
|
||||
C 3
|
||||
D 3
|
||||
BCD 3
|
361
supportlibs/pegmarkdown/peg-0.1.9/examples/basic.leg
Normal file
361
supportlibs/pegmarkdown/peg-0.1.9/examples/basic.leg
Normal file
@ -0,0 +1,361 @@
|
||||
# A 'syntax-directed interpreter' (all execution is a side-effect of parsing).
|
||||
# Inspired by Dennis Allison's original Tiny BASIC grammar, circa 1975.
|
||||
#
|
||||
# Copyright (c) 2007 by Ian Piumarta
|
||||
# All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a
|
||||
# copy of this software and associated documentation files (the 'Software'),
|
||||
# to deal in the Software without restriction, including without limitation
|
||||
# the rights to use, copy, modify, merge, publish, distribute, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, provided that the above copyright notice(s) and this
|
||||
# permission notice appear in all copies of the Software. Acknowledgement
|
||||
# of the use of this Software in supporting documentation would be
|
||||
# appreciated but is not required.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK.
|
||||
#
|
||||
# Last edited: 2012-04-29 15:14:06 by piumarta on emilia
|
||||
|
||||
%{
|
||||
# include <stdio.h>
|
||||
|
||||
typedef struct line line;
|
||||
|
||||
struct line
|
||||
{
|
||||
int number;
|
||||
int length;
|
||||
char *text;
|
||||
};
|
||||
|
||||
line *lines= 0;
|
||||
int numLines= 0;
|
||||
int pc= -1, epc= -1;
|
||||
int batch= 0;
|
||||
|
||||
int nextline(char *buf, int max);
|
||||
|
||||
# define min(x, y) ((x) < (y) ? (x) : (y))
|
||||
|
||||
# define YY_INPUT(buf, result, max_size) \
|
||||
{ \
|
||||
if ((pc >= 0) && (pc < numLines)) \
|
||||
{ \
|
||||
line *linep= lines+pc++; \
|
||||
result= min(max_size, linep->length); \
|
||||
memcpy(buf, linep->text, result); \
|
||||
} \
|
||||
else \
|
||||
result= nextline(buf, max_size); \
|
||||
}
|
||||
|
||||
union value {
|
||||
int number;
|
||||
char *string;
|
||||
int (*binop)(int lhs, int rhs);
|
||||
};
|
||||
|
||||
# define YYSTYPE union value
|
||||
|
||||
int variables[26];
|
||||
|
||||
void accept(int number, char *line);
|
||||
|
||||
void save(char *name);
|
||||
void load(char *name);
|
||||
void type(char *name);
|
||||
|
||||
int lessThan(int lhs, int rhs) { return lhs < rhs; }
|
||||
int lessEqual(int lhs, int rhs) { return lhs <= rhs; }
|
||||
int notEqual(int lhs, int rhs) { return lhs != rhs; }
|
||||
int equalTo(int lhs, int rhs) { return lhs == rhs; }
|
||||
int greaterEqual(int lhs, int rhs) { return lhs >= rhs; }
|
||||
int greaterThan(int lhs, int rhs) { return lhs > rhs; }
|
||||
|
||||
int input(void);
|
||||
|
||||
int stack[1024], sp= 0;
|
||||
|
||||
char *help;
|
||||
|
||||
void error(char *fmt, ...);
|
||||
int findLine(int n, int create);
|
||||
%}
|
||||
|
||||
line = - s:statement CR
|
||||
| - n:number < ( !CR . )* CR > { accept(n.number, yytext); }
|
||||
| - CR
|
||||
| - < ( !CR . )* CR > { epc= pc; error("syntax error"); }
|
||||
| - !. { exit(0); }
|
||||
|
||||
statement = 'print'- expr-list
|
||||
| 'if'- e1:expression r:relop e2:expression { if (!r.binop(e1.number, e2.number)) yythunkpos= 0; }
|
||||
'then'- statement
|
||||
| 'goto'- e:expression { epc= pc; if ((pc= findLine(e.number, 0)) < 0) error("no such line"); }
|
||||
| 'input'- var-list
|
||||
| 'let'- v:var EQUAL e:expression { variables[v.number]= e.number; }
|
||||
| 'gosub'- e:expression { epc= pc; if (sp < 1024) stack[sp++]= pc, pc= findLine(e.number, 0); else error("too many gosubs");
|
||||
if (pc < 0) error("no such line"); }
|
||||
| 'return'- { epc= pc; if ((pc= sp ? stack[--sp] : -1) < 0) error("no gosub"); }
|
||||
| 'clear'- { while (numLines) accept(lines->number, "\n"); }
|
||||
| 'list'- { int i; for (i= 0; i < numLines; ++i) printf("%5d %s", lines[i].number, lines[i].text); }
|
||||
| 'run'- s:string { load(s.string); pc= 0; }
|
||||
| 'run'- { pc= 0; }
|
||||
| 'end'- { pc= -1; if (batch) exit(0); }
|
||||
| 'rem'- ( !CR . )*
|
||||
| ('bye'|'quit'|'exit')- { exit(0); }
|
||||
| 'save'- s:string { save(s.string); }
|
||||
| 'load'- s:string { load(s.string); }
|
||||
| 'type'- s:string { type(s.string); }
|
||||
| 'dir'- { system("ls *.bas"); }
|
||||
| 'help'- { fprintf(stderr, "%s", help); }
|
||||
|
||||
expr-list = ( e:string { printf("%s", e.string); }
|
||||
| e:expression { printf("%d", e.number); }
|
||||
)? ( COMMA ( e:string { printf("%s", e.string); }
|
||||
| e:expression { printf("%d", e.number); }
|
||||
)
|
||||
)* ( COMMA
|
||||
| !COMMA { printf("\n"); }
|
||||
)
|
||||
|
||||
var-list = v:var { variables[v.number]= input(); }
|
||||
( COMMA v:var { variables[v.number]= input(); }
|
||||
)*
|
||||
|
||||
expression = ( PLUS? l:term
|
||||
| MINUS l:term { l.number = -l.number }
|
||||
) ( PLUS r:term { l.number += r.number }
|
||||
| MINUS r:term { l.number -= r.number }
|
||||
)* { $$.number = l.number }
|
||||
|
||||
term = l:factor ( STAR r:factor { l.number *= r.number }
|
||||
| SLASH r:factor { l.number /= r.number }
|
||||
)* { $$.number = l.number }
|
||||
|
||||
factor = v:var { $$.number = variables[v.number] }
|
||||
| n:number
|
||||
| OPEN expression CLOSE
|
||||
|
||||
var = < [a-z] > - { $$.number = yytext[0] - 'a' }
|
||||
|
||||
number = < digit+ > - { $$.number = atoi(yytext); }
|
||||
|
||||
digit = [0-9]
|
||||
|
||||
string = '"' < [^\"]* > '"' - { $$.string = yytext; }
|
||||
|
||||
relop = '<=' - { $$.binop= lessEqual; }
|
||||
| '<>' - { $$.binop= notEqual; }
|
||||
| '<' - { $$.binop= lessThan; }
|
||||
| '>=' - { $$.binop= greaterEqual; }
|
||||
| '>' - { $$.binop= greaterThan; }
|
||||
| '=' - { $$.binop= equalTo; }
|
||||
|
||||
EQUAL = '=' - CLOSE = ')' - OPEN = '(' -
|
||||
SLASH = '/' - STAR = '*' - MINUS = '-' -
|
||||
PLUS = '+' - COMMA = ',' -
|
||||
|
||||
- = [ \t]*
|
||||
|
||||
CR = '\n' | '\r' | '\r\n'
|
||||
|
||||
%%
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
char *help=
|
||||
"print <num>|<string> [, <num>|<string> ...] [,]\n"
|
||||
"if <expr> <|<=|<>|=|>=|> <expr> then <stmt>\n"
|
||||
"input <var> [, <var> ...] let <var> = <expr>\n"
|
||||
"goto <expr> gosub <expr>\n"
|
||||
"end return\n"
|
||||
"list clear\n"
|
||||
"run [\"filename\"] rem <comment...>\n"
|
||||
"dir type \"filename\"\n"
|
||||
"save \"filename\" load \"filename\"\n"
|
||||
"bye|quit|exit help\n"
|
||||
;
|
||||
|
||||
void error(char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
if (epc > 0)
|
||||
fprintf(stderr, "\nline %d: %s", lines[epc-1].number, lines[epc-1].text);
|
||||
else
|
||||
fprintf(stderr, "\n");
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
epc= pc= -1;
|
||||
}
|
||||
|
||||
#ifdef USE_READLINE
|
||||
# include <readline/readline.h>
|
||||
# include <readline/history.h>
|
||||
#endif
|
||||
|
||||
int nextline(char *buf, int max)
|
||||
{
|
||||
pc= -1;
|
||||
if (batch) exit(0);
|
||||
if (isatty(fileno(stdin)))
|
||||
{
|
||||
# ifdef USE_READLINE
|
||||
char *line= readline(">");
|
||||
if (line)
|
||||
{
|
||||
int len= strlen(line);
|
||||
if (len >= max) len= max - 1;
|
||||
strncpy(buf, line, len);
|
||||
(buf)[len]= '\n';
|
||||
add_history(line);
|
||||
free(line);
|
||||
return len + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
# endif
|
||||
putchar('>');
|
||||
fflush(stdout);
|
||||
}
|
||||
return fgets(buf, max, stdin) ? strlen(buf) : 0;
|
||||
}
|
||||
|
||||
int maxLines= 0;
|
||||
|
||||
int findLine(int n, int create)
|
||||
{
|
||||
int lo= 0, hi= numLines - 1;
|
||||
while (lo <= hi)
|
||||
{
|
||||
int mid= (lo + hi) / 2, lno= lines[mid].number;
|
||||
if (lno > n)
|
||||
hi= mid - 1;
|
||||
else if (lno < n)
|
||||
lo= mid + 1;
|
||||
else
|
||||
return mid;
|
||||
}
|
||||
if (create)
|
||||
{
|
||||
if (numLines == maxLines)
|
||||
{
|
||||
maxLines *= 2;
|
||||
lines= realloc(lines, sizeof(line) * maxLines);
|
||||
}
|
||||
if (lo < numLines)
|
||||
memmove(lines + lo + 1, lines + lo, sizeof(line) * (numLines - lo));
|
||||
++numLines;
|
||||
lines[lo].number= n;
|
||||
lines[lo].text= 0;
|
||||
return lo;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void accept(int n, char *s)
|
||||
{
|
||||
if (s[0] < 32) /* delete */
|
||||
{
|
||||
int lno= findLine(n, 0);
|
||||
if (lno >= 0)
|
||||
{
|
||||
if (lno < numLines - 1)
|
||||
memmove(lines + lno, lines + lno + 1, sizeof(line) * (numLines - lno - 1));
|
||||
--numLines;
|
||||
}
|
||||
}
|
||||
else /* insert */
|
||||
{
|
||||
int lno= findLine(n, 1);
|
||||
if (lines[lno].text) free(lines[lno].text);
|
||||
lines[lno].length= strlen(s);
|
||||
lines[lno].text= strdup(s);
|
||||
}
|
||||
}
|
||||
|
||||
char *extend(char *name)
|
||||
{
|
||||
static char path[1024];
|
||||
int len= strlen(name);
|
||||
sprintf(path, "%s%s", name, (((len > 4) && !strcasecmp(".bas", name + len - 4)) ? "" : ".bas"));
|
||||
return path;
|
||||
}
|
||||
|
||||
void save(char *name)
|
||||
{
|
||||
FILE *f= fopen(name= extend(name), "w");
|
||||
if (!f)
|
||||
perror(name);
|
||||
else
|
||||
{
|
||||
int i;
|
||||
for (i= 0; i < numLines; ++i)
|
||||
fprintf(f, "%d %s", lines[i].number, lines[i].text);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
void load(char *name)
|
||||
{
|
||||
FILE *f= fopen(name= extend(name), "r");
|
||||
if (!f)
|
||||
perror(name);
|
||||
else
|
||||
{
|
||||
int lineNumber;
|
||||
char lineText[1024];
|
||||
while ((1 == fscanf(f, " %d ", &lineNumber)) && fgets(lineText, sizeof(lineText), f))
|
||||
accept(lineNumber, lineText);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
void type(char *name)
|
||||
{
|
||||
FILE *f= fopen(name= extend(name), "r");
|
||||
if (!f)
|
||||
perror(name);
|
||||
else
|
||||
{
|
||||
int c, d;
|
||||
while ((c= getc(f)) >= 0)
|
||||
putchar(d= c);
|
||||
fclose(f);
|
||||
if ('\n' != d && '\r' != d) putchar('\n');
|
||||
}
|
||||
}
|
||||
|
||||
int input(void)
|
||||
{
|
||||
char line[32];
|
||||
fgets(line, sizeof(line), stdin);
|
||||
return atoi(line);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
lines= malloc(sizeof(line) * (maxLines= 32));
|
||||
numLines= 0;
|
||||
|
||||
if (argc > 1)
|
||||
{
|
||||
batch= 1;
|
||||
while (argc-- > 1)
|
||||
load(*++argv);
|
||||
pc= 0;
|
||||
}
|
||||
|
||||
while (!feof(stdin))
|
||||
yyparse();
|
||||
|
||||
return 0;
|
||||
}
|
10
supportlibs/pegmarkdown/peg-0.1.9/examples/basic.ref
Normal file
10
supportlibs/pegmarkdown/peg-0.1.9/examples/basic.ref
Normal file
@ -0,0 +1,10 @@
|
||||
1
|
||||
2 4
|
||||
3 6 9
|
||||
4 8 12 16
|
||||
5 10 15 20 25
|
||||
6 12 18 24 30 36
|
||||
7 14 21 28 35 42 49
|
||||
8 16 24 32 40 48 56 64
|
||||
9 18 27 36 45 54 63 72 81
|
||||
10 20 30 40 50 60 70 80 90 100
|
8
supportlibs/pegmarkdown/peg-0.1.9/examples/bench.bas
Normal file
8
supportlibs/pegmarkdown/peg-0.1.9/examples/bench.bas
Normal file
@ -0,0 +1,8 @@
|
||||
100 let n=100000
|
||||
120 let m=0
|
||||
110 let s=0
|
||||
130 let m=m+1
|
||||
140 let s=s+m
|
||||
150 if m<n then goto 130
|
||||
160 print "interpreted ", n*3, " lines of code; answer is ", s
|
||||
170 end
|
46
supportlibs/pegmarkdown/peg-0.1.9/examples/calc.leg
Normal file
46
supportlibs/pegmarkdown/peg-0.1.9/examples/calc.leg
Normal file
@ -0,0 +1,46 @@
|
||||
%{
|
||||
#include <stdio.h>
|
||||
int vars[26];
|
||||
%}
|
||||
|
||||
Stmt = - e:Expr EOL { printf("%d\n", e); }
|
||||
| ( !EOL . )* EOL { printf("error\n"); }
|
||||
|
||||
Expr = i:ID ASSIGN s:Sum { $$= vars[i]= s; }
|
||||
| s:Sum { $$= s; }
|
||||
|
||||
Sum = l:Product
|
||||
( PLUS r:Product { l += r; }
|
||||
| MINUS r:Product { l -= r; }
|
||||
)* { $$= l; }
|
||||
|
||||
Product = l:Value
|
||||
( TIMES r:Value { l *= r; }
|
||||
| DIVIDE r:Value { l /= r; }
|
||||
)* { $$= l; }
|
||||
|
||||
Value = i:NUMBER { $$= atoi(yytext); }
|
||||
| i:ID !ASSIGN { $$= vars[i]; }
|
||||
| OPEN i:Expr CLOSE { $$= i; }
|
||||
|
||||
NUMBER = < [0-9]+ > - { $$= atoi(yytext); }
|
||||
ID = < [a-z] > - { $$= yytext[0] - 'a'; }
|
||||
ASSIGN = '=' -
|
||||
PLUS = '+' -
|
||||
MINUS = '-' -
|
||||
TIMES = '*' -
|
||||
DIVIDE = '/' -
|
||||
OPEN = '(' -
|
||||
CLOSE = ')' -
|
||||
|
||||
- = [ \t]*
|
||||
EOL = '\n' | '\r\n' | '\r' | ';'
|
||||
|
||||
%%
|
||||
|
||||
int main()
|
||||
{
|
||||
while (yyparse());
|
||||
|
||||
return 0;
|
||||
}
|
3
supportlibs/pegmarkdown/peg-0.1.9/examples/calc.ref
Normal file
3
supportlibs/pegmarkdown/peg-0.1.9/examples/calc.ref
Normal file
@ -0,0 +1,3 @@
|
||||
6
|
||||
7
|
||||
42
|
17
supportlibs/pegmarkdown/peg-0.1.9/examples/dc.c
Normal file
17
supportlibs/pegmarkdown/peg-0.1.9/examples/dc.c
Normal file
@ -0,0 +1,17 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int stack[1024];
|
||||
int stackp= -1;
|
||||
|
||||
int push(int n) { return stack[++stackp]= n; }
|
||||
int pop(void) { return stack[stackp--]; }
|
||||
|
||||
#include "dc.peg.c"
|
||||
|
||||
int main()
|
||||
{
|
||||
while (yyparse());
|
||||
|
||||
return 0;
|
||||
}
|
27
supportlibs/pegmarkdown/peg-0.1.9/examples/dc.peg
Normal file
27
supportlibs/pegmarkdown/peg-0.1.9/examples/dc.peg
Normal file
@ -0,0 +1,27 @@
|
||||
# Grammar
|
||||
|
||||
Expr <- SPACE Sum EOL { printf("%d\n", pop()); }
|
||||
/ (!EOL .)* EOL { printf("error\n"); }
|
||||
|
||||
Sum <- Product ( PLUS Product { int r= pop(), l= pop(); push(l + r); }
|
||||
/ MINUS Product { int r= pop(), l= pop(); push(l - r); }
|
||||
)*
|
||||
|
||||
Product <- Value ( TIMES Value { int r= pop(), l= pop(); push(l * r); }
|
||||
/ DIVIDE Value { int r= pop(), l= pop(); push(l / r); }
|
||||
)*
|
||||
|
||||
Value <- NUMBER { push(atoi(yytext)); }
|
||||
/ OPEN Sum CLOSE
|
||||
|
||||
# Lexemes
|
||||
|
||||
NUMBER <- < [0-9]+ > SPACE
|
||||
PLUS <- '+' SPACE
|
||||
MINUS <- '-' SPACE
|
||||
TIMES <- '*' SPACE
|
||||
DIVIDE <- '/' SPACE
|
||||
OPEN <- '(' SPACE
|
||||
CLOSE <- ')' SPACE
|
||||
SPACE <- [ \t]*
|
||||
EOL <- '\n' / '\r\n' / '\r'
|
1
supportlibs/pegmarkdown/peg-0.1.9/examples/dc.ref
Normal file
1
supportlibs/pegmarkdown/peg-0.1.9/examples/dc.ref
Normal file
@ -0,0 +1 @@
|
||||
42
|
20
supportlibs/pegmarkdown/peg-0.1.9/examples/dcv.c
Normal file
20
supportlibs/pegmarkdown/peg-0.1.9/examples/dcv.c
Normal file
@ -0,0 +1,20 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int stack[1024];
|
||||
int stackp= -1;
|
||||
int var= 0;
|
||||
int vars[26];
|
||||
|
||||
int push(int n) { return stack[++stackp]= n; }
|
||||
int pop(void) { return stack[stackp--]; }
|
||||
int top(void) { return stack[stackp]; }
|
||||
|
||||
#include "dcv.peg.c"
|
||||
|
||||
int main()
|
||||
{
|
||||
while (yyparse());
|
||||
|
||||
return 0;
|
||||
}
|
34
supportlibs/pegmarkdown/peg-0.1.9/examples/dcv.peg
Normal file
34
supportlibs/pegmarkdown/peg-0.1.9/examples/dcv.peg
Normal file
@ -0,0 +1,34 @@
|
||||
# Grammar
|
||||
|
||||
Stmt <- SPACE Expr EOL { printf("%d\n", pop()); }
|
||||
/ (!EOL .)* EOL { printf("error\n"); }
|
||||
|
||||
Expr <- ID { var= yytext[0] } ASSIGN Sum { vars[var - 'a']= top(); }
|
||||
/ Sum
|
||||
|
||||
Sum <- Product ( PLUS Product { int r= pop(), l= pop(); push(l + r); }
|
||||
/ MINUS Product { int r= pop(), l= pop(); push(l - r); }
|
||||
)*
|
||||
|
||||
Product <- Value ( TIMES Value { int r= pop(), l= pop(); push(l * r); }
|
||||
/ DIVIDE Value { int r= pop(), l= pop(); push(l / r); }
|
||||
)*
|
||||
|
||||
Value <- NUMBER { push(atoi(yytext)); }
|
||||
/ < ID > !ASSIGN { push(vars[yytext[0] - 'a']); }
|
||||
/ OPEN Expr CLOSE
|
||||
|
||||
# Lexemes
|
||||
|
||||
NUMBER <- < [0-9]+ > SPACE
|
||||
ID <- < [a-z] > SPACE
|
||||
ASSIGN <- '=' SPACE
|
||||
PLUS <- '+' SPACE
|
||||
MINUS <- '-' SPACE
|
||||
TIMES <- '*' SPACE
|
||||
DIVIDE <- '/' SPACE
|
||||
OPEN <- '(' SPACE
|
||||
CLOSE <- ')' SPACE
|
||||
|
||||
SPACE <- [ \t]*
|
||||
EOL <- '\n' / '\r\n' / '\r' / ';'
|
3
supportlibs/pegmarkdown/peg-0.1.9/examples/dcv.ref
Normal file
3
supportlibs/pegmarkdown/peg-0.1.9/examples/dcv.ref
Normal file
@ -0,0 +1,3 @@
|
||||
6
|
||||
7
|
||||
42
|
17
supportlibs/pegmarkdown/peg-0.1.9/examples/fibonacci.bas
Normal file
17
supportlibs/pegmarkdown/peg-0.1.9/examples/fibonacci.bas
Normal file
@ -0,0 +1,17 @@
|
||||
100 let n=32
|
||||
110 gosub 200
|
||||
120 print "fibonacci(",n,") = ", m
|
||||
130 end
|
||||
|
||||
200 let c=n
|
||||
210 let b=1
|
||||
220 if c<2 then goto 400
|
||||
230 let c=c-1
|
||||
240 let a=1
|
||||
300 let c=c-1
|
||||
310 let d=a+b
|
||||
320 let a=b
|
||||
330 let b=d+1
|
||||
340 if c<>0 then goto 300
|
||||
400 let m=b
|
||||
410 return
|
17
supportlibs/pegmarkdown/peg-0.1.9/examples/left.c
Normal file
17
supportlibs/pegmarkdown/peg-0.1.9/examples/left.c
Normal file
@ -0,0 +1,17 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#define YY_INPUT(buf, result, max) \
|
||||
{ \
|
||||
int c= getchar(); \
|
||||
result= (EOF == c) ? 0 : (*(buf)= c, 1); \
|
||||
if (EOF != c) printf("<%c>\n", c); \
|
||||
}
|
||||
|
||||
#include "left.peg.c"
|
||||
|
||||
int main()
|
||||
{
|
||||
printf(yyparse() ? "success\n" : "failure\n");
|
||||
|
||||
return 0;
|
||||
}
|
3
supportlibs/pegmarkdown/peg-0.1.9/examples/left.peg
Normal file
3
supportlibs/pegmarkdown/peg-0.1.9/examples/left.peg
Normal file
@ -0,0 +1,3 @@
|
||||
# Grammar
|
||||
|
||||
S <- (S 'a' / 'a') !'a'
|
13
supportlibs/pegmarkdown/peg-0.1.9/examples/localctx.c
Normal file
13
supportlibs/pegmarkdown/peg-0.1.9/examples/localctx.c
Normal file
@ -0,0 +1,13 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#define YY_CTX_LOCAL
|
||||
|
||||
#include "test.peg.c"
|
||||
|
||||
int main()
|
||||
{
|
||||
yycontext ctx;
|
||||
memset(&ctx, 0, sizeof(yycontext));
|
||||
while (yyparse(&ctx));
|
||||
return 0;
|
||||
}
|
10
supportlibs/pegmarkdown/peg-0.1.9/examples/localctx.ref
Normal file
10
supportlibs/pegmarkdown/peg-0.1.9/examples/localctx.ref
Normal file
@ -0,0 +1,10 @@
|
||||
a1 ab1 .
|
||||
a2 ac2 .
|
||||
a3 ad3 .
|
||||
a3 ae3 .
|
||||
a4 af4 afg4 .
|
||||
a4 af5 afh5 .
|
||||
a4 af4 afg4 .
|
||||
a4 af5 afh5 .
|
||||
af6 afi6 a6 .
|
||||
af6 af7 afj7 a6 .
|
11
supportlibs/pegmarkdown/peg-0.1.9/examples/rule.c
Normal file
11
supportlibs/pegmarkdown/peg-0.1.9/examples/rule.c
Normal file
@ -0,0 +1,11 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "rule.peg.c"
|
||||
|
||||
int main()
|
||||
{
|
||||
while (yyparse());
|
||||
|
||||
return 0;
|
||||
}
|
8
supportlibs/pegmarkdown/peg-0.1.9/examples/rule.peg
Normal file
8
supportlibs/pegmarkdown/peg-0.1.9/examples/rule.peg
Normal file
@ -0,0 +1,8 @@
|
||||
start <- abcd+
|
||||
|
||||
abcd <- 'a' { printf("A %d\n", yypos); } bc { printf("ABC %d\n", yypos); }
|
||||
/ 'b' { printf("B %d\n", yypos); } cd { printf("BCD %d\n", yypos); }
|
||||
|
||||
bc <- 'b' { printf("B %d\n", yypos); } 'c' { printf("C %d\n", yypos); }
|
||||
|
||||
cd <- 'c' { printf("C %d\n", yypos); } 'd' { printf("D %d\n", yypos); }
|
32
supportlibs/pegmarkdown/peg-0.1.9/examples/rule.ref
Normal file
32
supportlibs/pegmarkdown/peg-0.1.9/examples/rule.ref
Normal file
@ -0,0 +1,32 @@
|
||||
A 24
|
||||
B 24
|
||||
C 24
|
||||
ABC 24
|
||||
B 24
|
||||
C 24
|
||||
D 24
|
||||
BCD 24
|
||||
A 24
|
||||
B 24
|
||||
C 24
|
||||
ABC 24
|
||||
B 24
|
||||
C 24
|
||||
D 24
|
||||
BCD 24
|
||||
A 24
|
||||
B 24
|
||||
C 24
|
||||
ABC 24
|
||||
B 24
|
||||
C 24
|
||||
D 24
|
||||
BCD 24
|
||||
A 24
|
||||
B 24
|
||||
C 24
|
||||
ABC 24
|
||||
B 24
|
||||
C 24
|
||||
D 24
|
||||
BCD 24
|
12
supportlibs/pegmarkdown/peg-0.1.9/examples/test.bas
Normal file
12
supportlibs/pegmarkdown/peg-0.1.9/examples/test.bas
Normal file
@ -0,0 +1,12 @@
|
||||
10 let i=1
|
||||
20 gosub 100
|
||||
30 let i=i+1
|
||||
40 if i<=10 then goto 20
|
||||
50 end
|
||||
|
||||
100 let j=1
|
||||
110 print " ", i*j,
|
||||
120 let j=j+1
|
||||
130 if j<=i then goto 110
|
||||
140 print
|
||||
150 return
|
8
supportlibs/pegmarkdown/peg-0.1.9/examples/test.c
Normal file
8
supportlibs/pegmarkdown/peg-0.1.9/examples/test.c
Normal file
@ -0,0 +1,8 @@
|
||||
#include <stdio.h>
|
||||
#include "test.peg.c"
|
||||
|
||||
int main()
|
||||
{
|
||||
while (yyparse());
|
||||
return 0;
|
||||
}
|
13
supportlibs/pegmarkdown/peg-0.1.9/examples/test.peg
Normal file
13
supportlibs/pegmarkdown/peg-0.1.9/examples/test.peg
Normal file
@ -0,0 +1,13 @@
|
||||
start <- body '.' { printf(".\n"); }
|
||||
|
||||
body <- 'a' { printf("a1 "); } 'b' { printf("ab1 "); }
|
||||
|
||||
/ 'a' { printf("a2 "); } 'c' { printf("ac2 "); }
|
||||
|
||||
/ 'a' { printf("a3 "); } ( 'd' { printf("ad3 "); } / 'e' { printf("ae3 "); } )
|
||||
|
||||
/ 'a' { printf("a4 "); } ( 'f' { printf("af4 "); } 'g' { printf("afg4 "); }
|
||||
/ 'f' { printf("af5 "); } 'h' { printf("afh5 "); } )
|
||||
|
||||
/ 'a' { printf("a6 "); } ( 'f' &{ printf("af6 ") } 'i' &{ printf("afi6 ") }
|
||||
/ 'f' &{ printf("af7 ") } 'j' &{ printf("afj7 ") } )
|
10
supportlibs/pegmarkdown/peg-0.1.9/examples/test.ref
Normal file
10
supportlibs/pegmarkdown/peg-0.1.9/examples/test.ref
Normal file
@ -0,0 +1,10 @@
|
||||
a1 ab1 .
|
||||
a2 ac2 .
|
||||
a3 ad3 .
|
||||
a3 ae3 .
|
||||
a4 af4 afg4 .
|
||||
a4 af5 afh5 .
|
||||
a4 af4 afg4 .
|
||||
a4 af5 afh5 .
|
||||
af6 afi6 a6 .
|
||||
af6 af7 afj7 a6 .
|
14
supportlibs/pegmarkdown/peg-0.1.9/examples/username.leg
Normal file
14
supportlibs/pegmarkdown/peg-0.1.9/examples/username.leg
Normal file
@ -0,0 +1,14 @@
|
||||
%{
|
||||
#include <unistd.h>
|
||||
%}
|
||||
|
||||
start = "username" { printf("%s", getlogin()); }
|
||||
| < . > { putchar(yytext[0]); }
|
||||
|
||||
%%
|
||||
|
||||
int main()
|
||||
{
|
||||
while (yyparse());
|
||||
return 0;
|
||||
}
|
22
supportlibs/pegmarkdown/peg-0.1.9/examples/wc.leg
Normal file
22
supportlibs/pegmarkdown/peg-0.1.9/examples/wc.leg
Normal file
@ -0,0 +1,22 @@
|
||||
%{
|
||||
#include <stdio.h>
|
||||
int lines= 0, words= 0, chars= 0;
|
||||
%}
|
||||
|
||||
start = (line | word | char)
|
||||
|
||||
line = < (( '\n' '\r'* ) | ( '\r' '\n'* )) > { lines++; chars += yyleng; }
|
||||
word = < [a-zA-Z]+ > { words++; chars += yyleng; printf("<%s>\n", yytext); }
|
||||
char = . { chars++; }
|
||||
|
||||
%%
|
||||
|
||||
int main()
|
||||
{
|
||||
while (yyparse())
|
||||
;
|
||||
printf("%d lines\n", lines);
|
||||
printf("%d chars\n", chars);
|
||||
printf("%d words\n", words);
|
||||
return 0;
|
||||
}
|
55
supportlibs/pegmarkdown/peg-0.1.9/examples/wc.ref
Normal file
55
supportlibs/pegmarkdown/peg-0.1.9/examples/wc.ref
Normal file
@ -0,0 +1,55 @@
|
||||
<include>
|
||||
<stdio>
|
||||
<h>
|
||||
<int>
|
||||
<lines>
|
||||
<words>
|
||||
<chars>
|
||||
<start>
|
||||
<line>
|
||||
<word>
|
||||
<char>
|
||||
<line>
|
||||
<n>
|
||||
<r>
|
||||
<r>
|
||||
<n>
|
||||
<lines>
|
||||
<chars>
|
||||
<yyleng>
|
||||
<word>
|
||||
<a>
|
||||
<zA>
|
||||
<Z>
|
||||
<words>
|
||||
<chars>
|
||||
<yyleng>
|
||||
<printf>
|
||||
<s>
|
||||
<n>
|
||||
<yytext>
|
||||
<char>
|
||||
<chars>
|
||||
<int>
|
||||
<main>
|
||||
<while>
|
||||
<yyparse>
|
||||
<printf>
|
||||
<d>
|
||||
<lines>
|
||||
<n>
|
||||
<lines>
|
||||
<printf>
|
||||
<d>
|
||||
<chars>
|
||||
<n>
|
||||
<chars>
|
||||
<printf>
|
||||
<d>
|
||||
<words>
|
||||
<n>
|
||||
<words>
|
||||
<return>
|
||||
22 lines
|
||||
425 chars
|
||||
52 words
|
1209
supportlibs/pegmarkdown/peg-0.1.9/leg.c
Normal file
1209
supportlibs/pegmarkdown/peg-0.1.9/leg.c
Normal file
File diff suppressed because it is too large
Load Diff
292
supportlibs/pegmarkdown/peg-0.1.9/leg.leg
Normal file
292
supportlibs/pegmarkdown/peg-0.1.9/leg.leg
Normal file
@ -0,0 +1,292 @@
|
||||
# LE Grammar for LE Grammars
|
||||
#
|
||||
# Copyright (c) 2007 by Ian Piumarta
|
||||
# All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a
|
||||
# copy of this software and associated documentation files (the 'Software'),
|
||||
# to deal in the Software without restriction, including without limitation
|
||||
# the rights to use, copy, modify, merge, publish, distribute, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, provided that the above copyright notice(s) and this
|
||||
# permission notice appear in all copies of the Software. Acknowledgement
|
||||
# of the use of this Software in supporting documentation would be
|
||||
# appreciated but is not required.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK.
|
||||
#
|
||||
# Last edited: 2012-04-29 15:51:15 by piumarta on emilia
|
||||
|
||||
%{
|
||||
# include "tree.h"
|
||||
# include "version.h"
|
||||
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
# include <unistd.h>
|
||||
# include <string.h>
|
||||
# include <libgen.h>
|
||||
# include <assert.h>
|
||||
|
||||
typedef struct Header Header;
|
||||
|
||||
struct Header {
|
||||
char *text;
|
||||
Header *next;
|
||||
};
|
||||
|
||||
FILE *input= 0;
|
||||
|
||||
int verboseFlag= 0;
|
||||
|
||||
static int lineNumber= 0;
|
||||
static char *fileName= 0;
|
||||
static char *trailer= 0;
|
||||
static Header *headers= 0;
|
||||
|
||||
void makeHeader(char *text);
|
||||
void makeTrailer(char *text);
|
||||
|
||||
void yyerror(char *message);
|
||||
|
||||
# define YY_INPUT(buf, result, max) \
|
||||
{ \
|
||||
int c= getc(input); \
|
||||
if ('\n' == c || '\r' == c) ++lineNumber; \
|
||||
result= (EOF == c) ? 0 : (*(buf)= c, 1); \
|
||||
}
|
||||
|
||||
# define YY_LOCAL(T) static T
|
||||
# define YY_RULE(T) static T
|
||||
%}
|
||||
|
||||
# Hierarchical syntax
|
||||
|
||||
grammar= - ( declaration | definition )+ trailer? end-of-file
|
||||
|
||||
declaration= '%{' < ( !'%}' . )* > RPERCENT { makeHeader(yytext); } #{YYACCEPT}
|
||||
|
||||
trailer= '%%' < .* > { makeTrailer(yytext); } #{YYACCEPT}
|
||||
|
||||
definition= identifier { if (push(beginRule(findRule(yytext)))->rule.expression)
|
||||
fprintf(stderr, "rule '%s' redefined\n", yytext); }
|
||||
EQUAL expression { Node *e= pop(); Rule_setExpression(pop(), e); }
|
||||
SEMICOLON? #{YYACCEPT}
|
||||
|
||||
expression= sequence (BAR sequence { Node *f= pop(); push(Alternate_append(pop(), f)); }
|
||||
)*
|
||||
|
||||
sequence= prefix (prefix { Node *f= pop(); push(Sequence_append(pop(), f)); }
|
||||
)*
|
||||
|
||||
prefix= AND action { push(makePredicate(yytext)); }
|
||||
| AND suffix { push(makePeekFor(pop())); }
|
||||
| NOT suffix { push(makePeekNot(pop())); }
|
||||
| suffix
|
||||
|
||||
suffix= primary (QUESTION { push(makeQuery(pop())); }
|
||||
| STAR { push(makeStar (pop())); }
|
||||
| PLUS { push(makePlus (pop())); }
|
||||
)?
|
||||
|
||||
primary= identifier { push(makeVariable(yytext)); }
|
||||
COLON identifier !EQUAL { Node *name= makeName(findRule(yytext)); name->name.variable= pop(); push(name); }
|
||||
| identifier !EQUAL { push(makeName(findRule(yytext))); }
|
||||
| OPEN expression CLOSE
|
||||
| literal { push(makeString(yytext)); }
|
||||
| class { push(makeClass(yytext)); }
|
||||
| DOT { push(makeDot()); }
|
||||
| action { push(makeAction(yytext)); }
|
||||
| BEGIN { push(makePredicate("YY_BEGIN")); }
|
||||
| END { push(makePredicate("YY_END")); }
|
||||
|
||||
# Lexical syntax
|
||||
|
||||
identifier= < [-a-zA-Z_][-a-zA-Z_0-9]* > -
|
||||
|
||||
literal= ['] < ( !['] char )* > ['] -
|
||||
| ["] < ( !["] char )* > ["] -
|
||||
|
||||
class= '[' < ( !']' range )* > ']' -
|
||||
|
||||
range= char '-' char | char
|
||||
|
||||
char= '\\' [-abefnrtv'"\[\]\\]
|
||||
| '\\' [0-3][0-7][0-7]
|
||||
| '\\' [0-7][0-7]?
|
||||
| !'\\' .
|
||||
|
||||
action= '{' < braces* > '}' -
|
||||
|
||||
braces= '{' braces* '}'
|
||||
| !'}' .
|
||||
|
||||
EQUAL= '=' -
|
||||
COLON= ':' -
|
||||
SEMICOLON= ';' -
|
||||
BAR= '|' -
|
||||
AND= '&' -
|
||||
NOT= '!' -
|
||||
QUESTION= '?' -
|
||||
STAR= '*' -
|
||||
PLUS= '+' -
|
||||
OPEN= '(' -
|
||||
CLOSE= ')' -
|
||||
DOT= '.' -
|
||||
BEGIN= '<' -
|
||||
END= '>' -
|
||||
RPERCENT= '%}' -
|
||||
|
||||
-= (space | comment)*
|
||||
space= ' ' | '\t' | end-of-line
|
||||
comment= '#' (!end-of-line .)* end-of-line
|
||||
end-of-line= '\r\n' | '\n' | '\r'
|
||||
end-of-file= !.
|
||||
|
||||
%%
|
||||
|
||||
void yyerror(char *message)
|
||||
{
|
||||
fprintf(stderr, "%s:%d: %s", fileName, lineNumber, message);
|
||||
if (yyctx->text[0]) fprintf(stderr, " near token '%s'", yyctx->text);
|
||||
if (yyctx->pos < yyctx->limit || !feof(input))
|
||||
{
|
||||
yyctx->buf[yyctx->limit]= '\0';
|
||||
fprintf(stderr, " before text \"");
|
||||
while (yyctx->pos < yyctx->limit)
|
||||
{
|
||||
if ('\n' == yyctx->buf[yyctx->pos] || '\r' == yyctx->buf[yyctx->pos]) break;
|
||||
fputc(yyctx->buf[yyctx->pos++], stderr);
|
||||
}
|
||||
if (yyctx->pos == yyctx->limit)
|
||||
{
|
||||
int c;
|
||||
while (EOF != (c= fgetc(input)) && '\n' != c && '\r' != c)
|
||||
fputc(c, stderr);
|
||||
}
|
||||
fputc('\"', stderr);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void makeHeader(char *text)
|
||||
{
|
||||
Header *header= (Header *)malloc(sizeof(Header));
|
||||
header->text= strdup(text);
|
||||
header->next= headers;
|
||||
headers= header;
|
||||
}
|
||||
|
||||
void makeTrailer(char *text)
|
||||
{
|
||||
trailer= strdup(text);
|
||||
}
|
||||
|
||||
static void version(char *name)
|
||||
{
|
||||
printf("%s version %d.%d.%d\n", name, PEG_MAJOR, PEG_MINOR, PEG_LEVEL);
|
||||
}
|
||||
|
||||
static void usage(char *name)
|
||||
{
|
||||
version(name);
|
||||
fprintf(stderr, "usage: %s [<option>...] [<file>...]\n", name);
|
||||
fprintf(stderr, "where <option> can be\n");
|
||||
fprintf(stderr, " -h print this help information\n");
|
||||
fprintf(stderr, " -o <ofile> write output to <ofile>\n");
|
||||
fprintf(stderr, " -v be verbose\n");
|
||||
fprintf(stderr, " -V print version number and exit\n");
|
||||
fprintf(stderr, "if no <file> is given, input is read from stdin\n");
|
||||
fprintf(stderr, "if no <ofile> is given, output is written to stdout\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
Node *n;
|
||||
int c;
|
||||
|
||||
output= stdout;
|
||||
input= stdin;
|
||||
lineNumber= 1;
|
||||
fileName= "<stdin>";
|
||||
|
||||
while (-1 != (c= getopt(argc, argv, "Vho:v")))
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'V':
|
||||
version(basename(argv[0]));
|
||||
exit(0);
|
||||
|
||||
case 'h':
|
||||
usage(basename(argv[0]));
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
if (!(output= fopen(optarg, "w")))
|
||||
{
|
||||
perror(optarg);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
verboseFlag= 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "for usage try: %s -h\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc)
|
||||
{
|
||||
for (; argc; --argc, ++argv)
|
||||
{
|
||||
if (!strcmp(*argv, "-"))
|
||||
{
|
||||
input= stdin;
|
||||
fileName= "<stdin>";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(input= fopen(*argv, "r")))
|
||||
{
|
||||
perror(*argv);
|
||||
exit(1);
|
||||
}
|
||||
fileName= *argv;
|
||||
}
|
||||
lineNumber= 1;
|
||||
if (!yyparse())
|
||||
yyerror("syntax error");
|
||||
if (input != stdin)
|
||||
fclose(input);
|
||||
}
|
||||
}
|
||||
else
|
||||
if (!yyparse())
|
||||
yyerror("syntax error");
|
||||
|
||||
if (verboseFlag)
|
||||
for (n= rules; n; n= n->any.next)
|
||||
Rule_print(n);
|
||||
|
||||
Rule_compile_c_header();
|
||||
|
||||
for (; headers; headers= headers->next)
|
||||
fprintf(output, "%s\n", headers->text);
|
||||
|
||||
if (rules)
|
||||
Rule_compile_c(rules);
|
||||
|
||||
if (trailer)
|
||||
fprintf(output, "%s\n", trailer);
|
||||
|
||||
return 0;
|
||||
}
|
933
supportlibs/pegmarkdown/peg-0.1.9/peg.1
Normal file
933
supportlibs/pegmarkdown/peg-0.1.9/peg.1
Normal file
@ -0,0 +1,933 @@
|
||||
.\" Copyright (c) 2007 by Ian Piumarta
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Permission is hereby granted, free of charge, to any person obtaining a
|
||||
.\" copy of this software and associated documentation files (the 'Software'),
|
||||
.\" to deal in the Software without restriction, including without limitation
|
||||
.\" the rights to use, copy, modify, merge, publish, distribute, and/or sell
|
||||
.\" copies of the Software, and to permit persons to whom the Software is
|
||||
.\" furnished to do so, provided that the above copyright notice(s) and this
|
||||
.\" permission notice appear in all copies of the Software. Acknowledgement
|
||||
.\" of the use of this Software in supporting documentation would be
|
||||
.\" appreciated but is not required.
|
||||
.\"
|
||||
.\" THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK.
|
||||
.\"
|
||||
.\" Last edited: 2012-04-29 16:58:44 by piumarta on emilia
|
||||
.\"
|
||||
.TH PEG 1 "April 2012" "Version 0.1"
|
||||
.SH NAME
|
||||
peg, leg \- parser generators
|
||||
.SH SYNOPSIS
|
||||
.B peg
|
||||
.B [\-hvV \-ooutput]
|
||||
.I [filename ...]
|
||||
.sp 0
|
||||
.B leg
|
||||
.B [\-hvV \-ooutput]
|
||||
.I [filename ...]
|
||||
.SH DESCRIPTION
|
||||
.I peg
|
||||
and
|
||||
.I leg
|
||||
are tools for generating recursive-descent parsers: programs that
|
||||
perform pattern matching on text. They process a Parsing Expression
|
||||
Grammar (PEG) [Ford 2004] to produce a program that recognises legal
|
||||
sentences of that grammar.
|
||||
.I peg
|
||||
processes PEGs written using the original syntax described by Ford;
|
||||
.I leg
|
||||
processes PEGs written using slightly different syntax and conventions
|
||||
that are intended to make it an attractive replacement for parsers
|
||||
built with
|
||||
.IR lex (1)
|
||||
and
|
||||
.IR yacc (1).
|
||||
Unlike
|
||||
.I lex
|
||||
and
|
||||
.IR yacc ,
|
||||
.I peg
|
||||
and
|
||||
.I leg
|
||||
support unlimited backtracking, provide ordered choice as a means for
|
||||
disambiguation, and can combine scanning (lexical analysis) and
|
||||
parsing (syntactic analysis) into a single activity.
|
||||
.PP
|
||||
.I peg
|
||||
reads the specified
|
||||
.IR filename s,
|
||||
or standard input if no
|
||||
.IR filename s
|
||||
are given, for a grammar describing the parser to generate.
|
||||
.I peg
|
||||
then generates a C source file that defines a function
|
||||
.IR yyparse().
|
||||
This C source file can be included in, or compiled and then linked
|
||||
with, a client program. Each time the client program calls
|
||||
.IR yyparse ()
|
||||
the parser consumes input text according to the parsing rules,
|
||||
starting from the first rule in the grammar.
|
||||
.IR yyparse ()
|
||||
returns non-zero if the input could be parsed according to the
|
||||
grammar; it returns zero if the input could not be parsed.
|
||||
.PP
|
||||
The prefix 'yy' or 'YY' is prepended to all externally-visible symbols
|
||||
in the generated parser. This is intended to reduce the risk of
|
||||
namespace pollution in client programs. (The choice of 'yy' is
|
||||
historical; see
|
||||
.IR lex (1)
|
||||
and
|
||||
.IR yacc (1),
|
||||
for example.)
|
||||
.SH OPTIONS
|
||||
.I peg
|
||||
and
|
||||
.I leg
|
||||
provide the following options:
|
||||
.TP
|
||||
.B \-h
|
||||
prints a summary of available options and then exits.
|
||||
.TP
|
||||
.B \-ooutput
|
||||
writes the generated parser to the file
|
||||
.B output
|
||||
instead of the standard output.
|
||||
.TP
|
||||
.B \-v
|
||||
writes verbose information to standard error while working.
|
||||
.TP
|
||||
.B \-V
|
||||
writes version information to standard error then exits.
|
||||
.SH A SIMPLE EXAMPLE
|
||||
The following
|
||||
.I peg
|
||||
input specifies a grammar with a single rule (called 'start') that is
|
||||
satisfied when the input contains the string "username".
|
||||
.nf
|
||||
|
||||
start <- "username"
|
||||
|
||||
.fi
|
||||
(The quotation marks are
|
||||
.I not
|
||||
part of the matched text; they serve to indicate a literal string to
|
||||
be matched.) In other words,
|
||||
.IR yyparse ()
|
||||
in the generated C source will return non-zero only if the next eight
|
||||
characters read from the input spell the word "username". If the
|
||||
input contains anything else,
|
||||
.IR yyparse ()
|
||||
returns zero and no input will have been consumed. (Subsequent calls
|
||||
to
|
||||
.IR yyparse ()
|
||||
will also return zero, since the parser is effectively blocked looking
|
||||
for the string "username".) To ensure progress we can add an
|
||||
alternative clause to the 'start' rule that will match any single
|
||||
character if "username" is not found.
|
||||
.nf
|
||||
|
||||
start <- "username"
|
||||
/ .
|
||||
|
||||
.fi
|
||||
.IR yyparse ()
|
||||
now always returns non-zero (except at the very end of the input). To
|
||||
do something useful we can add actions to the rules. These actions
|
||||
are performed after a complete match is found (starting from the first
|
||||
rule) and are chosen according to the 'path' taken through the grammar
|
||||
to match the input. (Linguists would call this path a 'phrase
|
||||
marker'.)
|
||||
.nf
|
||||
|
||||
start <- "username" { printf("%s\\n", getlogin()); }
|
||||
/ < . > { putchar(yytext[0]); }
|
||||
|
||||
.fi
|
||||
The first line instructs the parser to print the user's login name
|
||||
whenever it sees "username" in the input. If that match fails, the
|
||||
second line tells the parser to echo the next character on the input
|
||||
the standard output. Our parser is now performing useful work: it
|
||||
will copy the input to the output, replacing all occurrences of
|
||||
"username" with the user's account name.
|
||||
.PP
|
||||
Note the angle brackets ('<' and '>') that were added to the second
|
||||
alternative. These have no effect on the meaning of the rule, but
|
||||
serve to delimit the text made available to the following action in
|
||||
the variable
|
||||
.IR yytext .
|
||||
.PP
|
||||
If the above grammar is placed in the file
|
||||
.BR username.peg ,
|
||||
running the command
|
||||
.nf
|
||||
|
||||
peg -o username.c username.peg
|
||||
|
||||
.fi
|
||||
will save the corresponding parser in the file
|
||||
.BR username.c .
|
||||
To create a complete program this parser could be included by a C
|
||||
program as follows.
|
||||
.nf
|
||||
|
||||
#include <stdio.h> /* printf(), putchar() */
|
||||
#include <unistd.h> /* getlogin() */
|
||||
|
||||
#include "username.c" /* yyparse() */
|
||||
|
||||
int main()
|
||||
{
|
||||
while (yyparse()) /* repeat until EOF */
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
.fi
|
||||
.SH PEG GRAMMARS
|
||||
A grammar consists of a set of named rules.
|
||||
.nf
|
||||
|
||||
name <- pattern
|
||||
|
||||
.fi
|
||||
The
|
||||
.B pattern
|
||||
contains one or more of the following elements.
|
||||
.TP
|
||||
.B name
|
||||
The element stands for the entire pattern in the rule with the given
|
||||
.BR name .
|
||||
.TP
|
||||
.BR \(dq characters \(dq
|
||||
A character or string enclosed in double quotes is matched literally.
|
||||
The ANSI C esacpe sequences are recognised within the
|
||||
.IR characters .
|
||||
.TP
|
||||
.BR ' characters '
|
||||
A character or string enclosed in single quotes is matched literally, as above.
|
||||
.TP
|
||||
.BR [ characters ]
|
||||
A set of characters enclosed in square brackets matches any single
|
||||
character from the set, with escape characters recognised as above.
|
||||
If the set begins with an uparrow (^) then the set is negated (the
|
||||
element matches any character
|
||||
.I not
|
||||
in the set). Any pair of characters separated with a dash (-)
|
||||
represents the range of characters from the first to the second,
|
||||
inclusive. A single alphabetic character or underscore is matched by
|
||||
the following set.
|
||||
.nf
|
||||
|
||||
[a-zA-Z_]
|
||||
|
||||
.fi
|
||||
Similarly, the following matches any single non-digit character.
|
||||
.nf
|
||||
|
||||
[^0-9]
|
||||
|
||||
.fi
|
||||
.TP
|
||||
.B .
|
||||
A dot matches any character. Note that the only time this fails is at
|
||||
the end of file, where there is no character to match.
|
||||
.TP
|
||||
.BR ( \ pattern\ )
|
||||
Parentheses are used for grouping (modifying the precendence of the
|
||||
operators described below).
|
||||
.TP
|
||||
.BR { \ action\ }
|
||||
Curly braces surround actions. The action is arbitray C source code
|
||||
to be executed at the end of matching. Any braces within the action
|
||||
must be properly nested. Any input text that was matched before the
|
||||
action and delimited by angle brackets (see below) is made available
|
||||
within the action as the contents of the character array
|
||||
.IR yytext .
|
||||
The length of (number of characters in)
|
||||
.I yytext
|
||||
is available in the variable
|
||||
.IR yyleng .
|
||||
(These variable names are historical; see
|
||||
.IR lex (1).)
|
||||
.TP
|
||||
.B <
|
||||
An opening angle bracket always matches (consuming no input) and
|
||||
causes the parser to begin accumulating matched text. This text will
|
||||
be made available to actions in the variable
|
||||
.IR yytext .
|
||||
.TP
|
||||
.B >
|
||||
A closing angle bracket always matches (consuming no input) and causes
|
||||
the parser to stop accumulating text for
|
||||
.IR yytext .
|
||||
.PP
|
||||
The above
|
||||
.IR element s
|
||||
can be made optional and/or repeatable with the following suffixes:
|
||||
.TP
|
||||
.RB element\ ?
|
||||
The element is optional. If present on the input, it is consumed and
|
||||
the match succeeds. If not present on the input, no text is consumed
|
||||
and the match succeeds anyway.
|
||||
.TP
|
||||
.RB element\ +
|
||||
The element is repeatable. If present on the input, one or more
|
||||
occurrences of
|
||||
.I element
|
||||
are consumed and the match succeeds. If no occurrences of
|
||||
.I element
|
||||
are present on the input, the match fails.
|
||||
.TP
|
||||
.RB element\ *
|
||||
The element is optional and repeatable. If present on the input, one or more
|
||||
occurrences of
|
||||
.I element
|
||||
are consumed and the match succeeds. If no occurrences of
|
||||
.I element
|
||||
are present on the input, the match succeeds anyway.
|
||||
.PP
|
||||
The above elements and suffixes can be converted into predicates (that
|
||||
match arbitray input text and subsequently succeed or fail
|
||||
.I without
|
||||
consuming that input) with the following prefixes:
|
||||
.TP
|
||||
.BR & \ element
|
||||
The predicate succeeds only if
|
||||
.I element
|
||||
can be matched. Input text scanned while matching
|
||||
.I element
|
||||
is not consumed from the input and remains available for subsequent
|
||||
matching.
|
||||
.TP
|
||||
.BR ! \ element
|
||||
The predicate succeeds only if
|
||||
.I element
|
||||
cannot be matched. Input text scanned while matching
|
||||
.I element
|
||||
is not consumed from the input and remains available for subsequent
|
||||
matching. A popular idiom is
|
||||
.nf
|
||||
|
||||
!.
|
||||
|
||||
.fi
|
||||
which matches the end of file, after the last character of the input
|
||||
has already been consumed.
|
||||
.PP
|
||||
A special form of the '&' predicate is provided:
|
||||
.TP
|
||||
.BR & {\ expression\ }
|
||||
In this predicate the simple C
|
||||
.I expression
|
||||
.RB ( not
|
||||
statement) is evaluated immediately when the parser reaches the
|
||||
predicate. If the
|
||||
.I expression
|
||||
yields non-zero (true) the 'match' succeeds and the parser continues
|
||||
with the next element in the pattern. If the
|
||||
.I expression
|
||||
yields zero (false) the 'match' fails and the parser backs up to look
|
||||
for an alternative parse of the input.
|
||||
.PP
|
||||
Several elements (with or without prefixes and suffixes) can be
|
||||
combined into a
|
||||
.I sequence
|
||||
by writing them one after the other. The entire sequence matches only
|
||||
if each individual element within it matches, from left to right.
|
||||
.PP
|
||||
Sequences can be separated into disjoint alternatives by the
|
||||
alternation operator '/'.
|
||||
.TP
|
||||
.RB sequence-1\ / \ sequence-2\ / \ ...\ / \ sequence-N
|
||||
Each sequence is tried in turn until one of them matches, at which
|
||||
time matching for the overall pattern succeeds. If none of the
|
||||
sequences matches then the match of the overall pattern fails.
|
||||
.PP
|
||||
Finally, the pound sign (#) introduces a comment (discarded) that
|
||||
continues until the end of the line.
|
||||
.PP
|
||||
To summarise the above, the parser tries to match the input text
|
||||
against a pattern containing literals, names (representing other
|
||||
rules), and various operators (written as prefixes, suffixes,
|
||||
juxtaposition for sequencing and and infix alternation operator) that
|
||||
modify how the elements within the pattern are matched. Matches are
|
||||
made from left to right, 'descending' into named sub-rules as they are
|
||||
encountered. If the matching process fails, the parser 'back tracks'
|
||||
('rewinding' the input appropriately in the process) to find the
|
||||
nearest alternative 'path' through the grammar. In other words the
|
||||
parser performs a depth-first, left-to-right search for the first
|
||||
successfully-matching path through the rules. If found, the actions
|
||||
along the successful path are executed (in the order they were
|
||||
encountered).
|
||||
.PP
|
||||
Note that predicates are evaluated
|
||||
.I immediately
|
||||
during the search for a successful match, since they contribute to the
|
||||
success or failure of the search. Actions, however, are evaluated
|
||||
only after a successful match has been found.
|
||||
.SH PEG GRAMMAR FOR PEG GRAMMARS
|
||||
The grammar for
|
||||
.I peg
|
||||
grammars is shown below. This will both illustrate and formalise
|
||||
the above description.
|
||||
.nf
|
||||
|
||||
Grammar <- Spacing Definition+ EndOfFile
|
||||
|
||||
Definition <- Identifier LEFTARROW Expression
|
||||
Expression <- Sequence ( SLASH Sequence )*
|
||||
Sequence <- Prefix*
|
||||
Prefix <- AND Action
|
||||
/ ( AND | NOT )? Suffix
|
||||
Suffix <- Primary ( QUERY / STAR / PLUS )?
|
||||
Primary <- Identifier !LEFTARROW
|
||||
/ OPEN Expression CLOSE
|
||||
/ Literal
|
||||
/ Class
|
||||
/ DOT
|
||||
/ Action
|
||||
/ BEGIN
|
||||
/ END
|
||||
|
||||
Identifier <- < IdentStart IdentCont* > Spacing
|
||||
IdentStart <- [a-zA-Z_]
|
||||
IdentCont <- IdentStart / [0-9]
|
||||
Literal <- ['] < ( !['] Char )* > ['] Spacing
|
||||
/ ["] < ( !["] Char )* > ["] Spacing
|
||||
Class <- '[' < ( !']' Range )* > ']' Spacing
|
||||
Range <- Char '-' Char / Char
|
||||
Char <- '\\\\' [abefnrtv'"\\[\\]\\\\]
|
||||
/ '\\\\' [0-3][0-7][0-7]
|
||||
/ '\\\\' [0-7][0-7]?
|
||||
/ '\\\\' '-'
|
||||
/ !'\\\\' .
|
||||
LEFTARROW <- '<-' Spacing
|
||||
SLASH <- '/' Spacing
|
||||
AND <- '&' Spacing
|
||||
NOT <- '!' Spacing
|
||||
QUERY <- '?' Spacing
|
||||
STAR <- '*' Spacing
|
||||
PLUS <- '+' Spacing
|
||||
OPEN <- '(' Spacing
|
||||
CLOSE <- ')' Spacing
|
||||
DOT <- '.' Spacing
|
||||
Spacing <- ( Space / Comment )*
|
||||
Comment <- '#' ( !EndOfLine . )* EndOfLine
|
||||
Space <- ' ' / '\\t' / EndOfLine
|
||||
EndOfLine <- '\\r\\n' / '\\n' / '\\r'
|
||||
EndOfFile <- !.
|
||||
Action <- '{' < [^}]* > '}' Spacing
|
||||
BEGIN <- '<' Spacing
|
||||
END <- '>' Spacing
|
||||
|
||||
.fi
|
||||
.SH LEG GRAMMARS
|
||||
.I leg
|
||||
is a variant of
|
||||
.I peg
|
||||
that adds some features of
|
||||
.IR lex (1)
|
||||
and
|
||||
.IR yacc (1).
|
||||
It differs from
|
||||
.I peg
|
||||
in the following ways.
|
||||
.TP
|
||||
.BI %{\ text... \ %}
|
||||
A declaration section can appear anywhere that a rule definition is
|
||||
expected. The
|
||||
.I text
|
||||
between the delimiters '%{' and '%}' is copied verbatim to the
|
||||
generated C parser code
|
||||
.I before
|
||||
the code that implements the parser itself.
|
||||
.TP
|
||||
.IB name\ = \ pattern
|
||||
The 'assignment' operator replaces the left arrow operator '<-'.
|
||||
.TP
|
||||
.B rule-name
|
||||
Hyphens can appear as letters in the names of rules. Each hyphen is
|
||||
converted into an underscore in the generated C source code. A single
|
||||
single hyphen '-' is a legal rule name.
|
||||
.nf
|
||||
|
||||
- = [ \\t\\n\\r]*
|
||||
number = [0-9]+ -
|
||||
name = [a-zA-Z_][a-zA_Z_0-9]* -
|
||||
l-paren = '(' -
|
||||
r-paren = ')' -
|
||||
|
||||
.fi
|
||||
This example shows how ignored whitespace can be obvious when reading
|
||||
the grammar and yet unobtrusive when placed liberally at the end of
|
||||
every rule associated with a lexical element.
|
||||
.TP
|
||||
.IB seq-1\ | \ seq-2
|
||||
The alternation operator is vertical bar '|' rather than forward
|
||||
slash '/'. The
|
||||
.I peg
|
||||
rule
|
||||
.nf
|
||||
|
||||
name <- sequence-1
|
||||
/ sequence-2
|
||||
/ sequence-3
|
||||
|
||||
.fi
|
||||
is therefore written
|
||||
.nf
|
||||
|
||||
name = sequence-1
|
||||
| sequence-2
|
||||
| sequence-3
|
||||
;
|
||||
|
||||
.fi
|
||||
in
|
||||
.I leg
|
||||
(with the final semicolon being optional, as described next).
|
||||
.TP
|
||||
.IB pattern\ ;
|
||||
A semicolon punctuator can optionally terminate a
|
||||
.IR pattern .
|
||||
.TP
|
||||
.BI %% \ text...
|
||||
A double percent '%%' terminates the rules (and declarations) section of
|
||||
the grammar. All
|
||||
.I text
|
||||
following '%%' is copied verbatim to the generated C parser code
|
||||
.I after
|
||||
the parser implementation code.
|
||||
.TP
|
||||
.BI $$\ = \ value
|
||||
A sub-rule can return a semantic
|
||||
.I value
|
||||
from an action by assigning it to the pseudo-variable '$$'. All
|
||||
semantic values must have the same type (which defaults to 'int').
|
||||
This type can be changed by defining YYSTYPE in a declaration section.
|
||||
.TP
|
||||
.IB identifier : name
|
||||
The semantic value returned (by assigning to '$$') from the sub-rule
|
||||
.I name
|
||||
is associated with the
|
||||
.I identifier
|
||||
and can be referred to in subsequent actions.
|
||||
.PP
|
||||
The desk calclator example below illustrates the use of '$$' and ':'.
|
||||
.SH LEG EXAMPLE: A DESK CALCULATOR
|
||||
The extensions in
|
||||
.I leg
|
||||
described above allow useful parsers and evaluators (including
|
||||
declarations, grammar rules, and supporting C functions such
|
||||
as 'main') to be kept within a single source file. To illustrate this
|
||||
we show a simple desk calculator supporting the four common arithmetic
|
||||
operators and named variables. The intermediate results of arithmetic
|
||||
evaluation will be accumulated on an implicit stack by returning them
|
||||
as semantic values from sub-rules.
|
||||
.nf
|
||||
|
||||
%{
|
||||
#include <stdio.h> /* printf() */
|
||||
#include <stdlib.h> /* atoi() */
|
||||
int vars[26];
|
||||
%}
|
||||
|
||||
Stmt = - e:Expr EOL { printf("%d\\n", e); }
|
||||
| ( !EOL . )* EOL { printf("error\\n"); }
|
||||
|
||||
Expr = i:ID ASSIGN s:Sum { $$ = vars[i] = s; }
|
||||
| s:Sum { $$ = s; }
|
||||
|
||||
Sum = l:Product
|
||||
( PLUS r:Product { l += r; }
|
||||
| MINUS r:Product { l -= r; }
|
||||
)* { $$ = l; }
|
||||
|
||||
Product = l:Value
|
||||
( TIMES r:Value { l *= r; }
|
||||
| DIVIDE r:Value { l /= r; }
|
||||
)* { $$ = l; }
|
||||
|
||||
Value = i:NUMBER { $$ = atoi(yytext); }
|
||||
| i:ID !ASSIGN { $$ = vars[i]; }
|
||||
| OPEN i:Expr CLOSE { $$ = i; }
|
||||
|
||||
NUMBER = < [0-9]+ > - { $$ = atoi(yytext); }
|
||||
ID = < [a-z] > - { $$ = yytext[0] - 'a'; }
|
||||
ASSIGN = '=' -
|
||||
PLUS = '+' -
|
||||
MINUS = '-' -
|
||||
TIMES = '*' -
|
||||
DIVIDE = '/' -
|
||||
OPEN = '(' -
|
||||
CLOSE = ')' -
|
||||
|
||||
- = [ \\t]*
|
||||
EOL = '\\n' | '\\r\\n' | '\\r' | ';'
|
||||
|
||||
%%
|
||||
|
||||
int main()
|
||||
{
|
||||
while (yyparse())
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
|
||||
.fi
|
||||
.SH LEG GRAMMAR FOR LEG GRAMMARS
|
||||
The grammar for
|
||||
.I leg
|
||||
grammars is shown below. This will both illustrate and formalise the
|
||||
above description.
|
||||
.nf
|
||||
|
||||
grammar = -
|
||||
( declaration | definition )+
|
||||
trailer? end-of-file
|
||||
|
||||
declaration = '%{' < ( !'%}' . )* > RPERCENT
|
||||
|
||||
trailer = '%%' < .* >
|
||||
|
||||
definition = identifier EQUAL expression SEMICOLON?
|
||||
|
||||
expression = sequence ( BAR sequence )*
|
||||
|
||||
sequence = prefix+
|
||||
|
||||
prefix = AND action
|
||||
| ( AND | NOT )? suffix
|
||||
|
||||
suffix = primary ( QUERY | STAR | PLUS )?
|
||||
|
||||
primary = identifier COLON identifier !EQUAL
|
||||
| identifier !EQUAL
|
||||
| OPEN expression CLOSE
|
||||
| literal
|
||||
| class
|
||||
| DOT
|
||||
| action
|
||||
| BEGIN
|
||||
| END
|
||||
|
||||
identifier = < [-a-zA-Z_][-a-zA-Z_0-9]* > -
|
||||
|
||||
literal = ['] < ( !['] char )* > ['] -
|
||||
| ["] < ( !["] char )* > ["] -
|
||||
|
||||
class = '[' < ( !']' range )* > ']' -
|
||||
|
||||
range = char '-' char | char
|
||||
|
||||
char = '\\\\' [abefnrtv'"\\[\\]\\\\]
|
||||
| '\\\\' [0-3][0-7][0-7]
|
||||
| '\\\\' [0-7][0-7]?
|
||||
| !'\\\\' .
|
||||
|
||||
action = '{' < [^}]* > '}' -
|
||||
|
||||
EQUAL = '=' -
|
||||
COLON = ':' -
|
||||
SEMICOLON = ';' -
|
||||
BAR = '|' -
|
||||
AND = '&' -
|
||||
NOT = '!' -
|
||||
QUERY = '?' -
|
||||
STAR = '*' -
|
||||
PLUS = '+' -
|
||||
OPEN = '(' -
|
||||
CLOSE = ')' -
|
||||
DOT = '.' -
|
||||
BEGIN = '<' -
|
||||
END = '>' -
|
||||
RPERCENT = '%}' -
|
||||
|
||||
- = ( space | comment )*
|
||||
space = ' ' | '\\t' | end-of-line
|
||||
comment = '#' ( !end-of-line . )* end-of-line
|
||||
end-of-line = '\\r\\n' | '\\n' | '\\r'
|
||||
end-of-file = !.
|
||||
|
||||
.fi
|
||||
.SH CUSTOMISING THE PARSER
|
||||
The following symbols can be redefined in declaration sections to
|
||||
modify the generated parser code.
|
||||
.TP
|
||||
.B YYSTYPE
|
||||
The semantic value type. The pseudo-variable '$$' and the
|
||||
identifiers 'bound' to rule results with the colon operator ':' should
|
||||
all be considered as being declared to have this type. The default
|
||||
value is 'int'.
|
||||
.TP
|
||||
.B YYPARSE
|
||||
The name of the main entry point to the parser. The default value
|
||||
is 'yyparse'.
|
||||
.TP
|
||||
.B YYPARSEFROM
|
||||
The name of an alternative entry point to the parser. This function
|
||||
expects one argument: the function corresponding to the rule from
|
||||
which the search for a match should begin. The default
|
||||
is 'yyparsefrom'. Note that yyparse() is defined as
|
||||
.nf
|
||||
|
||||
int yyparse() { return yyparsefrom(yy_foo); }
|
||||
|
||||
.fi
|
||||
where 'foo' is the name of the first rule in the grammar.
|
||||
.TP
|
||||
.BI YY_INPUT( buf , \ result , \ max_size )
|
||||
This macro is invoked by the parser to obtain more input text.
|
||||
.I buf
|
||||
points to an area of memory that can hold at most
|
||||
.I max_size
|
||||
characters. The macro should copy input text to
|
||||
.I buf
|
||||
and then assign the integer variable
|
||||
.I result
|
||||
to indicate the number of characters copied. If no more input is available,
|
||||
the macro should assign 0 to
|
||||
.IR result .
|
||||
By default, the YY_INPUT macro is defined as follows.
|
||||
.nf
|
||||
|
||||
#define YY_INPUT(buf, result, max_size) \\
|
||||
{ \\
|
||||
int yyc= getchar(); \\
|
||||
result= (EOF == yyc) ? 0 : (*(buf)= yyc, 1); \\
|
||||
}
|
||||
|
||||
.fi
|
||||
.TP
|
||||
.B YY_DEBUG
|
||||
If this symbols is defined then additional code will be included in
|
||||
the parser that prints vast quantities of arcane information to the
|
||||
standard error while the parser is running.
|
||||
.TP
|
||||
.B YY_BEGIN
|
||||
This macro is invoked to mark the start of input text that will be
|
||||
made available in actions as 'yytext'. This corresponds to
|
||||
occurrences of '<' in the grammar. These are converted into
|
||||
predicates that are expected to succeed. The default definition
|
||||
.nf
|
||||
|
||||
#define YY_BEGIN (yybegin= yypos, 1)
|
||||
|
||||
.fi
|
||||
therefore saves the current input position and returns 1 ('true') as
|
||||
the result of the predicate.
|
||||
.TP
|
||||
.B YY_END
|
||||
This macros corresponds to '>' in the grammar. Again, it is a
|
||||
predicate so the default definition saves the input position
|
||||
before 'succeeding'.
|
||||
.nf
|
||||
|
||||
#define YY_END (yyend= yypos, 1)
|
||||
|
||||
.fi
|
||||
.TP
|
||||
.BI YY_PARSE( T )
|
||||
This macro declares the parser entry points (yyparse and yyparsefrom)
|
||||
to be of type
|
||||
.IR T .
|
||||
The default definition
|
||||
.nf
|
||||
|
||||
#define YY_PARSE(T) T
|
||||
|
||||
.fi
|
||||
leaves yyparse() and yyparsefrom() with global visibility. If they
|
||||
should not be externally visible in other source files, this macro can
|
||||
be redefined to declare them 'static'.
|
||||
.nf
|
||||
|
||||
#define YY_PARSE(T) static T
|
||||
|
||||
.fi
|
||||
.TP
|
||||
.BI YY_CTX_LOCAL
|
||||
If this symbol is defined during compilation of a generated parser
|
||||
then global parser state will be kept in a structure of
|
||||
type 'yycontext' which can be declared as a local variable. This
|
||||
allows multiple instances of parsers to coexist and to be thread-safe.
|
||||
The parsing function
|
||||
.IR yyparse ()
|
||||
will be declared to expect a first argument of type 'yycontext *', an
|
||||
instance of the structure holding the global state for the parser.
|
||||
This instance must be allocated and initialised to zero by the client.
|
||||
A trivial but complete example is as follows.
|
||||
.nf
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define YY_CTX_LOCAL
|
||||
|
||||
#include "the-generated-parser.peg.c"
|
||||
|
||||
int main()
|
||||
{
|
||||
yycontext ctx;
|
||||
memset(&ctx, 0, sizeof(yycontext));
|
||||
while (yyparse(&ctx));
|
||||
return 0;
|
||||
}
|
||||
|
||||
.fi
|
||||
Note that if this symbol is undefined then the compiled parser will
|
||||
statically allocate its global state and will be neither reentrant nor
|
||||
thread-safe.
|
||||
.TP
|
||||
.BI YY_CTX_MEMBERS
|
||||
If YY_CTX_LOCAL is defined (see above) then the macro YY_CTX_MEMBERS
|
||||
can be defined to expand to any additional member field declarations
|
||||
that the client would like included in the declaration of
|
||||
the 'yycontext' structure type. These additional members are
|
||||
otherwise ignored by the generated parser. The instance
|
||||
of 'yycontext' associated with the currently-active parser is
|
||||
available in actions through the pointer variable
|
||||
.IR yyctx .
|
||||
.PP
|
||||
The following variables can be reffered to within actions.
|
||||
.TP
|
||||
.B char *yybuf
|
||||
This variable points to the parser's input buffer used to store input
|
||||
text that has not yet been matched.
|
||||
.TP
|
||||
.B int yypos
|
||||
This is the offset (in yybuf) of the next character to be matched and
|
||||
consumed.
|
||||
.TP
|
||||
.B char *yytext
|
||||
The most recent matched text delimited by '<' and '>' is stored in this variable.
|
||||
.TP
|
||||
.B int yyleng
|
||||
This variable indicates the number of characters in 'yytext'.
|
||||
.TP
|
||||
.B yycontext *yyctx
|
||||
This variable points to the instance of 'yycontext' associated with
|
||||
the currently-active parser.
|
||||
.SH DIAGNOSTICS
|
||||
.I peg
|
||||
and
|
||||
.I leg
|
||||
warn about the following conditions while converting a grammar into a parser.
|
||||
.TP
|
||||
.B syntax error
|
||||
The input grammar was malformed in some way. The error message will
|
||||
include the text about to be matched (often backed up a huge amount
|
||||
from the actual location of the error) and the line number of the most
|
||||
recently considered character (which is often the real location of the
|
||||
problem).
|
||||
.TP
|
||||
.B rule 'foo' used but not defined
|
||||
The grammar referred to a rule named 'foo' but no definition for it
|
||||
was given. Attempting to use the generated parser will likely result
|
||||
in errors from the linker due to undefined symbols associated with the
|
||||
missing rule.
|
||||
.TP
|
||||
.B rule 'foo' defined but not used
|
||||
The grammar defined a rule named 'foo' and then ignored it. The code
|
||||
associated with the rule is included in the generated parser which
|
||||
will in all other respects be healthy.
|
||||
.TP
|
||||
.B possible infinite left recursion in rule 'foo'
|
||||
There exists at least one path through the grammar that leads from the
|
||||
rule 'foo' back to (a recursive invocation of) the same rule without
|
||||
consuming any input.
|
||||
.PP
|
||||
Left recursion, especially that found in standards documents, is
|
||||
often 'direct' and implies trivial repetition.
|
||||
.nf
|
||||
|
||||
# (6.7.6)
|
||||
direct-abstract-declarator =
|
||||
LPAREN abstract-declarator RPAREN
|
||||
| direct-abstract-declarator? LBRACKET assign-expr? RBRACKET
|
||||
| direct-abstract-declarator? LBRACKET STAR RBRACKET
|
||||
| direct-abstract-declarator? LPAREN param-type-list? RPAREN
|
||||
|
||||
.fi
|
||||
The recursion can easily be eliminated by converting the parts of the
|
||||
pattern following the recursion into a repeatable suffix.
|
||||
.nf
|
||||
|
||||
# (6.7.6)
|
||||
direct-abstract-declarator =
|
||||
direct-abstract-declarator-head?
|
||||
direct-abstract-declarator-tail*
|
||||
|
||||
direct-abstract-declarator-head =
|
||||
LPAREN abstract-declarator RPAREN
|
||||
|
||||
direct-abstract-declarator-tail =
|
||||
LBRACKET assign-expr? RBRACKET
|
||||
| LBRACKET STAR RBRACKET
|
||||
| LPAREN param-type-list? RPAREN
|
||||
|
||||
.fi
|
||||
.SH BUGS
|
||||
The 'yy' and 'YY' prefixes cannot be changed.
|
||||
.PP
|
||||
Left recursion is detected in the input grammar but is not handled
|
||||
correctly in the generated parser.
|
||||
.PP
|
||||
Diagnostics for errors in the input grammar are obscure and not
|
||||
particularly helpful.
|
||||
.PP
|
||||
Several commonly-used
|
||||
.IR lex (1)
|
||||
features (yywrap(), yyin, etc.) are completely absent.
|
||||
.PP
|
||||
The generated parser foes not contain '#line' directives to direct C
|
||||
compiler errors back to the grammar description when appropriate.
|
||||
.IR lex (1)
|
||||
features (yywrap(), yyin, etc.) are completely absent.
|
||||
.SH SEE ALSO
|
||||
D. Val Schorre,
|
||||
.I META II, a syntax-oriented compiler writing language,
|
||||
19th ACM National Conference, 1964, pp.\ 41.301--41.311. Describes a
|
||||
self-implementing parser generator for analytic grammars with no
|
||||
backtracking.
|
||||
.PP
|
||||
Alexander Birman,
|
||||
.I The TMG Recognition Schema,
|
||||
Ph.D. dissertation, Princeton, 1970. A mathematical treatment of the
|
||||
power and complexity of recursive-descent parsing with backtracking.
|
||||
.PP
|
||||
Bryan Ford,
|
||||
.I Parsing Expression Grammars: A Recognition-Based Syntactic Foundation,
|
||||
ACM SIGPLAN Symposium on Principles of Programming Languages, 2004.
|
||||
Defines PEGs and analyses them in relation to context-free and regular
|
||||
grammars. Introduces the syntax adopted in
|
||||
.IR peg .
|
||||
.PP
|
||||
The standard Unix utilies
|
||||
.IR lex (1)
|
||||
and
|
||||
.IR yacc (1)
|
||||
which influenced the syntax and features of
|
||||
.IR leg .
|
||||
.PP
|
||||
The source code for
|
||||
.I peg
|
||||
and
|
||||
.I leg
|
||||
whose grammar parsers are written using themselves.
|
||||
.PP
|
||||
The latest version of this software and documentation:
|
||||
.nf
|
||||
|
||||
http://piumarta.com/software/peg
|
||||
|
||||
.fi
|
||||
.SH AUTHOR
|
||||
.IR peg ,
|
||||
.I leg
|
||||
and this manual page were written by Ian Piumarta (first-name at
|
||||
last-name dot com) while investigating the viablility of regular- and
|
||||
parsing-expression grammars for efficiently extracting type and
|
||||
signature information from C header files.
|
||||
.PP
|
||||
Please send bug reports and suggestions for improvements to the author
|
||||
at the above address.
|
173
supportlibs/pegmarkdown/peg-0.1.9/peg.c
Normal file
173
supportlibs/pegmarkdown/peg-0.1.9/peg.c
Normal file
@ -0,0 +1,173 @@
|
||||
/* Copyright (c) 2007 by Ian Piumarta
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the 'Software'),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, provided that the above copyright notice(s) and this
|
||||
* permission notice appear in all copies of the Software. Acknowledgement
|
||||
* of the use of this Software in supporting documentation would be
|
||||
* appreciated but is not required.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK.
|
||||
*
|
||||
* Last edited: 2012-04-29 15:49:09 by piumarta on emilia
|
||||
*/
|
||||
|
||||
#include "tree.h"
|
||||
#include "version.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <libgen.h>
|
||||
#include <assert.h>
|
||||
|
||||
FILE *input= 0;
|
||||
|
||||
int verboseFlag= 0;
|
||||
|
||||
static int lineNumber= 0;
|
||||
static char *fileName= 0;
|
||||
|
||||
void yyerror(char *message);
|
||||
|
||||
#define YY_INPUT(buf, result, max) \
|
||||
{ \
|
||||
int c= getc(input); \
|
||||
if ('\n' == c || '\r' == c) ++lineNumber; \
|
||||
result= (EOF == c) ? 0 : (*(buf)= c, 1); \
|
||||
}
|
||||
|
||||
#define YY_LOCAL(T) static T
|
||||
#define YY_RULE(T) static T
|
||||
|
||||
#include "peg.peg-c"
|
||||
|
||||
void yyerror(char *message)
|
||||
{
|
||||
fprintf(stderr, "%s:%d: %s", fileName, lineNumber, message);
|
||||
if (yyctx->text[0]) fprintf(stderr, " near token '%s'", yyctx->text);
|
||||
if (yyctx->pos < yyctx->limit || !feof(input))
|
||||
{
|
||||
yyctx->buf[yyctx->limit]= '\0';
|
||||
fprintf(stderr, " before text \"");
|
||||
while (yyctx->pos < yyctx->limit)
|
||||
{
|
||||
if ('\n' == yyctx->buf[yyctx->pos] || '\r' == yyctx->buf[yyctx->pos]) break;
|
||||
fputc(yyctx->buf[yyctx->pos++], stderr);
|
||||
}
|
||||
if (yyctx->pos == yyctx->limit)
|
||||
{
|
||||
int c;
|
||||
while (EOF != (c= fgetc(input)) && '\n' != c && '\r' != c)
|
||||
fputc(c, stderr);
|
||||
}
|
||||
fputc('\"', stderr);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void version(char *name)
|
||||
{
|
||||
printf("%s version %d.%d.%d\n", name, PEG_MAJOR, PEG_MINOR, PEG_LEVEL);
|
||||
}
|
||||
|
||||
static void usage(char *name)
|
||||
{
|
||||
version(name);
|
||||
fprintf(stderr, "usage: %s [<option>...] [<file>...]\n", name);
|
||||
fprintf(stderr, "where <option> can be\n");
|
||||
fprintf(stderr, " -h print this help information\n");
|
||||
fprintf(stderr, " -o <ofile> write output to <ofile>\n");
|
||||
fprintf(stderr, " -v be verbose\n");
|
||||
fprintf(stderr, " -V print version number and exit\n");
|
||||
fprintf(stderr, "if no <file> is given, input is read from stdin\n");
|
||||
fprintf(stderr, "if no <ofile> is given, output is written to stdout\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
Node *n;
|
||||
int c;
|
||||
|
||||
output= stdout;
|
||||
input= stdin;
|
||||
lineNumber= 1;
|
||||
fileName= "<stdin>";
|
||||
|
||||
while (-1 != (c= getopt(argc, argv, "Vho:v")))
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'V':
|
||||
version(basename(argv[0]));
|
||||
exit(0);
|
||||
|
||||
case 'h':
|
||||
usage(basename(argv[0]));
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
if (!(output= fopen(optarg, "w")))
|
||||
{
|
||||
perror(optarg);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
verboseFlag= 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "for usage try: %s -h\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc)
|
||||
{
|
||||
for (; argc; --argc, ++argv)
|
||||
{
|
||||
if (!strcmp(*argv, "-"))
|
||||
{
|
||||
input= stdin;
|
||||
fileName= "<stdin>";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(input= fopen(*argv, "r")))
|
||||
{
|
||||
perror(*argv);
|
||||
exit(1);
|
||||
}
|
||||
fileName= *argv;
|
||||
}
|
||||
lineNumber= 1;
|
||||
if (!yyparse())
|
||||
yyerror("syntax error");
|
||||
if (input != stdin)
|
||||
fclose(input);
|
||||
}
|
||||
}
|
||||
else
|
||||
if (!yyparse())
|
||||
yyerror("syntax error");
|
||||
|
||||
if (verboseFlag)
|
||||
for (n= rules; n; n= n->any.next)
|
||||
Rule_print(n);
|
||||
|
||||
Rule_compile_c_header();
|
||||
if (rules) Rule_compile_c(rules);
|
||||
|
||||
return 0;
|
||||
}
|
77
supportlibs/pegmarkdown/peg-0.1.9/peg.peg
Normal file
77
supportlibs/pegmarkdown/peg-0.1.9/peg.peg
Normal file
@ -0,0 +1,77 @@
|
||||
# PE Grammar for PE Grammars
|
||||
#
|
||||
# Adapted from [1] by Ian Piumarta <first-name at last-name point com>.
|
||||
#
|
||||
# Local modifications (marked '#ikp') to support:
|
||||
# C text in '{ ... }' copied verbatim to output as 'semantic action'
|
||||
# input consumed between '<' and '>' is 'char yytext[]' in semantic actions
|
||||
#
|
||||
# Best viewed using 140 columns monospaced with tabs every 8.
|
||||
#
|
||||
# [1] Bryan Ford. "Parsing Expression Grammars: A Recognition-Based Syntactic
|
||||
# Foundation." Symposium on Principles of Programming Languages,
|
||||
# January 14--16, 2004, Venice, Italy.
|
||||
#
|
||||
# Last edited: 2007-05-15 10:32:44 by piumarta on emilia
|
||||
|
||||
# Hierarchical syntax
|
||||
|
||||
Grammar <- Spacing Definition+ EndOfFile
|
||||
|
||||
Definition <- Identifier { if (push(beginRule(findRule(yytext)))->rule.expression) fprintf(stderr, "rule '%s' redefined\n", yytext); }
|
||||
LEFTARROW Expression { Node *e= pop(); Rule_setExpression(pop(), e); } &{ YYACCEPT }
|
||||
Expression <- Sequence (SLASH Sequence { Node *f= pop(); push(Alternate_append(pop(), f)); }
|
||||
)*
|
||||
Sequence <- Prefix (Prefix { Node *f= pop(); push(Sequence_append(pop(), f)); } #ikp expanded from 'Seq <- Prefix*'
|
||||
)*
|
||||
/ { push(makePredicate("1")); } #ikp added
|
||||
Prefix <- AND Action { push(makePredicate(yytext)); } #ikp added
|
||||
/ AND Suffix { push(makePeekFor(pop())); } #ikp expanded from 'Prefix <- (AND/NOT)? Suffix'
|
||||
/ NOT Suffix { push(makePeekNot(pop())); }
|
||||
/ Suffix
|
||||
Suffix <- Primary (QUESTION { push(makeQuery(pop())); }
|
||||
/ STAR { push(makeStar (pop())); }
|
||||
/ PLUS { push(makePlus (pop())); }
|
||||
)?
|
||||
Primary <- Identifier !LEFTARROW { push(makeName(findRule(yytext))); }
|
||||
/ OPEN Expression CLOSE
|
||||
/ Literal { push(makeString(yytext)); }
|
||||
/ Class { push(makeClass(yytext)); }
|
||||
/ DOT { push(makeDot()); }
|
||||
/ Action { push(makeAction(yytext)); } #ikp added
|
||||
/ BEGIN { push(makePredicate("YY_BEGIN")); } #ikp added
|
||||
/ END { push(makePredicate("YY_END")); } #ikp added
|
||||
|
||||
# Lexical syntax
|
||||
|
||||
Identifier <- < IdentStart IdentCont* > Spacing #ikp inserted < ... >
|
||||
IdentStart <- [a-zA-Z_]
|
||||
IdentCont <- IdentStart / [0-9]
|
||||
Literal <- ['] < (!['] Char )* > ['] Spacing #ikp inserted < ... >
|
||||
/ ["] < (!["] Char )* > ["] Spacing #ikp inserted < ... >
|
||||
Class <- '[' < (!']' Range)* > ']' Spacing #ikp inserted < ... >
|
||||
Range <- Char '-' Char / Char
|
||||
Char <- '\\' [abefnrtv'"\[\]\\] #ikp added missing ANSI escapes: abefv
|
||||
/ '\\' [0-3][0-7][0-7]
|
||||
/ '\\' [0-7][0-7]?
|
||||
/ '\\' '-' #ikp added
|
||||
/ !'\\' .
|
||||
LEFTARROW <- '<-' Spacing
|
||||
SLASH <- '/' Spacing
|
||||
AND <- '&' Spacing
|
||||
NOT <- '!' Spacing
|
||||
QUESTION <- '?' Spacing
|
||||
STAR <- '*' Spacing
|
||||
PLUS <- '+' Spacing
|
||||
OPEN <- '(' Spacing
|
||||
CLOSE <- ')' Spacing
|
||||
DOT <- '.' Spacing
|
||||
Spacing <- (Space / Comment)*
|
||||
Comment <- '#' (!EndOfLine .)* EndOfLine
|
||||
Space <- ' ' / '\t' / EndOfLine
|
||||
EndOfLine <- '\r\n' / '\n' / '\r'
|
||||
EndOfFile <- !.
|
||||
|
||||
Action <- '{' < [^}]* > '}' Spacing #ikp added
|
||||
BEGIN <- '<' Spacing #ikp added
|
||||
END <- '>' Spacing #ikp added
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user