Skip to content

Instantly share code, notes, and snippets.

@PRBorges
Last active May 17, 2023 20:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save PRBorges/d63e4451f953e861991f3f036e3ad784 to your computer and use it in GitHub Desktop.
Save PRBorges/d63e4451f953e861991f3f036e3ad784 to your computer and use it in GitHub Desktop.
A grammar for diff output in normal, unified, and git formats
(* EBNF grammar for diff output in normal, unified, and git formats *)
(* Author: Pedro R. Borges *)
(* Read the accompanying article at https://www.prborges.com/2023/grammar-for-diff-output *)
diff = emptyDiff | normalDiff | uniDiff | gitDiff ;
(* 1. Empty diff *)
emptyDiff = "" ;
(* 2. Normal format *)
normalDiff = normalHunk , {normalHunk } ;
normalHunk = addHunk | deleteHunk | changeHunk ;
addHunk =
number , 'a' , range , eol ,
addedLines ,
[ noteLine ] ;
deleteHunk =
range , 'd' , number , eol ,
deletedLines ,
[ noteLine ] ;
changeHunk =
range , 'c' , range , eol ,
deletedLines ,
[ noteLine ] ,
"---" , eol ,
addedLines ,
[ noteLine ] ;
addedLines = addedLine , { addedLine } ;
addedLine = "> " , line , eol ;
deletedLines = deletedLine , { deletedLine } ;
deletedLine = "< " , line , eol ;
(* 3. Unified and Git formats *)
uniDiff =
"--- " , fileInfo , eol ,
"+++ " , fileInfo , eol ,
uniHunk , { uniHunk } ;
gitDiff =
"diff --git " , filePath , ' ' , filePath , eol ,
"index " , commitHash , ' ' , commitHash , eol ,
"--- " , filePath , eol ,
"+++ " , filePath , eol ,
uniHunk , { uniHunk } ;
fileInfo = filePath , '\t' , timestamp ;
timestamp = date , ' ' , time24 , ' ' , timeZone ;
date = fourDigits , '-' , twoDigits , '-' , twoDigits ;
time24 = twoDigits , ':' , twoDigits , ':' , twoDigits , '.' , nineDigits ;
timeZone = ('+' | '-') , fourDigits ;
uniHunk =
uniHunkDescriptor , eol ,
{ contextLine } ,
lrGroup ,
{clrGroup } ,
[ contextLines , [ noteLine ] ] ;
uniHunkDescriptor= "@@ +" , range , " -" , range , " @@" , [section] ;
section = ' ' , line ;
clrGroup = contextLines , lrGroup ;
contextLines = contextLine , { contextLine } ;
contextLine = ' ' , line , eol ;
lrGroup
= leftLines
| rightLines
| leftLines , rightLines ;
leftLines =
leftLine ,
{ leftLine } ,
[ noteLine ] ;
leftLine = '-' , line , eol ;
rightLines =
rightLine ,
{ rightLine } ,
[ noteLine ] ;
rightLine = '+' , line , eol ;
(* 4. Common and auxiliary rules *)
range
= number
| number , ',' , number ;
(* Here, "\\ " is one backslash followed by a space *)
noteLine = "\\ " , note , eol ;
number
= '0'
| '1' .. '9' , { digit } ;
(* Ranges and * repetition are not allowed in some EBNF variants *)
digit = '0' .. '9' ;
twoDigits = 2 * digit ;
fourDigits = 4 * digit ;
nineDigits = 9 * digit ;
eol = '\n' ;
(* 5. Special rules *)
line = ? line from a diffed file without '\n' ? ;
note = ? note indicating no newline in last line of a file ? ;
filePath = ? file path string ? ;
commitHash = ? alphanumeric commit hash ? ;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment