Friday, August 26, 2011

ANTLR Tutorial - Hello Word

Antlr stands for ANother Tool for Language Recognition. The tool is able to generate compiler or interpreter for any computer language. Besides obvious use, e.g. need to parse a real 'big' programming language such as Java, PHP or SQL, it can help with smaller, more common tasks.

It is useful any time you need to evaluate expressions unknown at compile-time or to parse non-trivial user input or files in a weird format. Of course, it is possible to create custom hand made parser for any of these tasks. However, it usually takes much more time and effort. A little knowledge of a good parser generator may turn these time-consuming tasks into easy and fast exercises.

This post begins with a small demonstration of ANTLR usefulness. Then, we explain what ANTLR is and how does it work. Finally, we show how to compile a simple 'Hello word!' language into an abstract syntax tree. The post explains also how to add error handling and how to test the language.

Next post shows how to create a real expression language.

Real Word Examples

ANTLR seems to be popular in open source word. Among others, it is used by Apache Camel, Apache Lucene, Apache Hadoop, Groovy and Hibernate. They all needed parser for a custom language. For example, Hibernate uses ANTLR to parse its query language HQL.

All those are big frameworks and thus more likely to need domain specific language than small application. The list of smaller projects using ANTLR is available on its showcase list. We found also one stackoverflow discussion on the topic.

To see where ANTLR could be useful and how it could save time, try to estimate following requirements:
  • Add formula calculator into an accounting system. It will calculate values of formulas such as (10 + 80)*sales_tax.
  • Add extended search field into a recipe search engine. It will search for receipts matching expressions such as (chicken and orange) or (no meat and carrot).

Our safe estimate is a day and half including documentation, tests, and integration into the project. ANTLR is worth looking at if you are facing similar requirements and made significantly higher estimate.

Overview

ANTLR is code generator. It takes so called grammar file as input and generates two classes: lexer and parser.

Lexer runs first and splits input into pieces called tokens. Each token represents more or less meaningful piece of input. The stream of tokes is passed to parser which do all necessary work. It is the parser who builds abstract syntax tree, interprets the code or translate it into some other form.

Grammar file contains everything ANTLR needs to generate correct lexer and parser. Whether it should generate java or python classes, whether parser generates abstract syntax tree, assembler code or directly interprets code and so on. As this tutorial shows how to build abstract syntax tree, we will ignore other options in following explanations.

Most importantly, grammar file describes how to split input into tokens and how to build tree from tokens. In other words, grammar file contains lexer rules and parser rules.

Each lexer rule describes one token:
TokenName: regular expression;   

Parser rules are more complicated. The most basic version is similar as in lexer rule:
ParserRuleName: regular expression;   

They may contain modifiers that specify special transformations on input, root and childs in result abstract syntax tree or actions to be performed whenever rule is used. Almost all work is usually done inside parser rules.

Infrastructure

First, we show tools to make development with ANTLR easier. Of course, nothing of what is described in this chapter is necessary. All examples work with maven, text-editor and internet connection only.

ANTLR project produced stand alone IDE, Eclipse plugin and Idea plugin. We did not found NetBeans plugin.

ANTLRWorks
Stand alone ide is called ANTLRWorks. Download it from the project download page. ANTLRWorks is a single jar file, use java -jar antlrworks-1.4.3.jar command to run it.

The IDE has more features and is more stable than Eclipse plugin.

Eclipse Plugin
Download and unpack ANTLR v3 from ANTLR download page. Then, install ANTLR plugin from Eclipse Marketplace:

Go to Preferences and configure ANTLR v3 installation directory:

To test the configuration, download sample grammar file and open it in eclipse. It will be open it in ANTLR editor. The editor has three tabs:
  • Grammar - text editor with syntax highlighting, code completion and so on.
  • Interpreter - compiles test expressions into syntax trees, may produce different result than generated parser. It tend to throw failed predicate exception on correct expressions.
  • Railroad View - paints nice graphs of your lexer and parser rules.

An Empty Project - Maven Configuration

This chapter shows how to add ANTLR into a maven project. If you use Eclipse and do not have a m2eclipse plugin installed yet, install it from http://download.eclipse.org/technology/m2e/releases update site. It will make your life much easier.

Create Project
Create new maven project and specify maven-archetype-quickstart on 'Select an Archetype' screen. If you do not use Eclipse, command mvn archetype:generate achieves the same.

Dependency
Add ANTLR dependency into pom.xml:

  
    org.antlr
    antlr
    3.3
   jar
    compile
  


Note: As ANTLR does not have history of being backward-compatible, it is better to specify required version.

Plugins
Antlr maven plugin runs during generate-sources phase and generates both lexer and parser java classes from grammar (.g) files. Add it into pom.xml:

  org.antlr
  antlr3-maven-plugin
  3.3
  
    
      run antlr
      generate-sources
      
        antlr
      
    
  


Create src/main/antlr3 folder. The plugin expects all grammar files in there.

Generated files are put into target/generated-sources/antlr3 directory. As this directory is not in default maven build path, we use build-helper-maven-plugin to add it there:

  org.codehaus.mojo
  build-helper-maven-plugin
  
    
      add-source
      generate-sources
      
        add-source
      
      
        
          ${basedir}/target/generated-sources/antlr3
        
      
    
  


If you use eclipse, you have to update project configuration: right click on the project -> 'maven' -> 'Update Project Configuration'.

Test It
Invoke maven to test project configuration: right click on the project -> 'Run As' -> 'Maven generate-sources'. Alternatively, use mvn generate-sources command.

Build should be successful. Console output should contain antlr3-maven-plugin plugin output:
[INFO] --- antlr3-maven-plugin:3.3:antlr (run antlr) @ antlr-step-by-step ---
[INFO] ANTLR: Processing source directory C:\meri\ANTLR\workspace\antlr-step-by-step\src\main\antlr3
[INFO] No grammars to process
ANTLR Parser Generator  Version 3.3 Nov 30, 2010 12:46:29

It should be followed by build-helper-maven-plugin plugin output:
[INFO] --- build-helper-maven-plugin:1.7:add-source (add-source) @ antlr-step-by-step ---
[INFO] Source directory: C:\meri\ANTLR\workspace\antlr-step-by-step\target\generated-sources\antlr3 added.

The result of this phase in located on github, tag 001-configured_antlr.

Hello Word

We will create simplest possible language parser - hello word parser. It builds a small abstract syntax tree from a single expression: 'Hello word!'.

We will use it to show how to create a grammar file and generate ANTLR classes from it. Then, we will show how to use generated files and create an unit test.

First Grammar File
Antlr3-maven-plugin searches src/main/antlr3 directory for grammar files. It creates new package for each sub-directory with grammar and generates parser and lexer classes into it. As we wish to generate classes into org.meri.antlr_step_by_step.parsers package, we have to create src/main/antlr3/org/meri/antlr_step_by_step/parsers directory.

Grammar name and file name must be identical. File must have .g suffix. Moreover, each grammar file begins with a grammar name declaration. Our S001HelloWord grammar begins with following line:
grammar S001HelloWord;

Declaration is always followed by generator options. We are working on java project and wish to compile expressions into abstract syntax tree:
options {
    // antlr will generate java lexer and parser
    language = Java;
    // generated parser should create abstract syntax tree
    output = AST;
}

Antlr does not generate package declaration on top of generated classes. We have to use @parser::header and @lexer::header blocks to enforce it. Headers must follow options block:
@lexer::header {
  package org.meri.antlr_step_by_step.parsers;
}

@parser::header {
  package org.meri.antlr_step_by_step.parsers;
}

Each grammar file must have at least one lexer rule. Each lexer rule must begin with upper case letter. We have two rules, first defines a salutation token, second defines an endsymbol token. Salutation must be 'Hello word' and endsymbol must be '!'.
SALUTATION:'Hello word';   
ENDSYMBOL:'!';

Similarly, each grammar file must have at least one parser rule. Each parser rule must begin with lower case letter. We have only one parser rule: any expression in our language must be composed of a salutation followed by an endsymbol.
expression : SALUTATION ENDSYMBOL;

Note: the order of grammar file elements is fixed. If you change it, antlr plugin will fail.

Generate Lexer and Parser
Generate a lexer and parser from command line using mvn generate-sources command or from Eclipse:
  • Right click on the project.
  • Click 'Run As'.
  • Click 'Maven generate-sources'.

Antlr plugin will create target/generated-sources/antlr/org/meri/antlr_step_by_step/parsers folder and place S001HelloWordLexer.java and S001HelloWordParser.java files inside.

Use Lexer and Parser
Finally, we create compiler class. It has only one public method which:
  • calls generated lexer to split input into tokens,
  • calls generated parser to build AST from tokens,
  • prints result AST tree into console,
  • returns abstract syntax tree.

Compiler is located in S001HelloWordCompiler class:
public CommonTree compile(String expression) {
    try {
      //lexer splits input into tokens
      ANTLRStringStream input = new ANTLRStringStream(expression);
      TokenStream tokens = new CommonTokenStream( new S001HelloWordLexer( input ) );
  
      //parser generates abstract syntax tree
      S001HelloWordParser parser = new S001HelloWordParser(tokens);
      S001HelloWordParser.expression_return ret = parser.expression();
  
      //acquire parse result
      CommonTree ast = (CommonTree) ret.tree;
      printTree(ast);
      return ast;
    } catch (RecognitionException e) {
      throw new IllegalStateException("Recognition exception is never thrown, only declared.");
  }

Note: Do not worry about RecognitionException exception declared on S001HelloWordParser.expression() method. It is never thrown.

Testing It
We finish this chapter with a small test case for our new compiler. Create S001HelloWordTest class:
public class S001HelloWordTest {
 /**
  * Abstract syntax tree generated from "Hello word!" should have an 
  * unnamed root node with two children. First child corresponds to 
  * salutation token and second child corresponds to end symbol token.
  * 
  * Token type constants are defined in generated S001HelloWordParser 
  * class.
  */
 @Test
 public void testCorrectExpression() {
  //compile the expression
  S001HelloWordCompiler compiler = new S001HelloWordCompiler();
  CommonTree ast = compiler.compile("Hello word!");
  CommonTree leftChild = ast.getChild(0);
  CommonTree rightChild = ast.getChild(1);

  //check ast structure
  assertEquals(S001HelloWordParser.SALUTATION, leftChild.getType());
  assertEquals(S001HelloWordParser.ENDSYMBOL, rightChild.getType());
 }

}

The test will pass successfully. It will print abstract syntax tree to the console:
0 null
  -- 4 Hello word
  -- 5 !

Grammar in IDE
Open S001HelloWord.g in editor and go to interpreter tab.
  • Highlight expression rule in top left view.
  • Write 'Hello word!' into top right view.
  • Press green arrow in top left corner.

Interpreter will generate parse tree:

Copy Grammar

Each new grammar in this tutorial is based on previous one. We compiled a list of steps needed to copy an old grammar into a new one. Use them to copy an OldGrammar into a NewGrammar:

Error Handling

No task is really finished without an appropriate error handling. Generated ANTLR classes try to recover from errors whenever possible. They do report errors to the console, but there is no out-of-the box API to programmatically find about syntax errors.

This could be fine if we would build command line only compiler. However, lets assume that we are building a GUI to our language, or use the result as input to another tool. In such case, we need an API access to all generated errors.

In the beginning of this chapter, we will experiment with default error handling and create test case for it. Then, we will add a naive error handling, which will throw an exception whenever first error happens. Finally, we will move to the 'real' solution. It will collect all errors in an internal list and provide methods to access them.

As a side product, the chapter shows how to:

Default Error Handling
First, we will try to parse various incorrect expressions. The goal is to understand default ANTLR error handling behavior. We will create test case from each experiment. All test cases are located in S001HelloWordExperimentsTest class.

Expression 1: Hello word?
Result tree is very similar to the correct one:
0 null
  -- 4 Hello word
  -- 5 ?<missing ENDSYMBOL>

Console output contains errors:
line 1:10 no viable alternative at character '?'
line 1:11 missing ENDSYMBOL at '<eof>'

Test case: following test case passes with no problem. No exception is thrown and abstract syntax tree node types are the same as in correct expression.
@Test
 public void testSmallError() {
  //compile the expression
  S001HelloWordCompiler compiler = new S001HelloWordCompiler();
  CommonTree ast = compiler.compile("Hello word?");

  //check AST structure
  assertEquals(S001HelloWordParser.SALUTATION, ast.getChild(0).getType());
  assertEquals(S001HelloWordParser.ENDSYMBOL, ast.getChild(1).getType());
 }

Expression 2: Bye!
Result tree is very similar to the correct one:
0 null
  -- 4 
  -- 5 !

Console output contains errors:
line 1:0 no viable alternative at character 'B'
line 1:1 no viable alternative at character 'y'
line 1:2 no viable alternative at character 'e'
line 1:3 missing SALUTATION at '!'

Test case: following test case passes with no problem. No exception is thrown and abstract syntax tree node types are the same as in correct expression.
@Test
 public void testBiggerError() {
  //compile the expression
  S001HelloWordCompiler compiler = new S001HelloWordCompiler();
  CommonTree ast = compiler.compile("Bye!");

  //check AST structure
  assertEquals(S001HelloWordParser.SALUTATION, ast.getChild(0).getType());
  assertEquals(S001HelloWordParser.ENDSYMBOL, ast.getChild(1).getType());
 }

Expression 3: Incorrect Expression
Result tree has only root node with no childs:
0 

Console output contains a lot of errors:
line 1:0 no viable alternative at character 'I'
line 1:1 no viable alternative at character 'n'
line 1:2 no viable alternative at character 'c'
line 1:3 no viable alternative at character 'o'
line 1:4 no viable alternative at character 'r'
line 1:5 no viable alternative at character 'r'
line 1:6 no viable alternative at character 'e'
line 1:7 no viable alternative at character 'c'
line 1:8 no viable alternative at character 't'
line 1:9 no viable alternative at character ' '
line 1:10 no viable alternative at character 'E'
line 1:11 no viable alternative at character 'x'
line 1:12 no viable alternative at character 'p'
line 1:13 no viable alternative at character 'r'
line 1:14 no viable alternative at character 'e'
line 1:15 no viable alternative at character 's'
line 1:16 no viable alternative at character 's'
line 1:17 no viable alternative at character 'i'
line 1:18 no viable alternative at character 'o'
line 1:19 no viable alternative at character 'n'
line 1:20 mismatched input '&ltEOF>' expecting SALUTATION

Test case: we finally found an expression that results in different tree structure.
@Test
 public void testCompletelyWrong() {
  //compile the expression
  S001HelloWordCompiler compiler = new S001HelloWordCompiler();
  CommonTree ast = compiler.compile("Incorrect Expression");

  //check AST structure
  assertEquals(0, ast.getChildCount());
 }

Error Handling in Lexer
Each lexer rule 'RULE' corresponds to 'mRULE' method in generated lexer. For example, our grammar has two rules:
SALUTATION:'Hello word';   
ENDSYMBOL:'!';

and generated lexer has two corresponding methods:
public final void mSALUTATION() throws RecognitionException {
    // ...
}

public final void mENDSYMBOL() throws RecognitionException {
    // ...
}

Depending on what exception is thrown, lexer may or may not try to recover from it. However, each error ends in reportError(RecognitionException e) method. Generated lexer inherits it:
public void reportError(RecognitionException e) {
  displayRecognitionError(this.getTokenNames(), e);
 }

The result: we have to change either reportError or displayRecognitionError method in lexer.

Error Handling in Parser
Our grammar has only one parser rule 'expression':
expression SALUTATION ENDSYMBOL;

The expression corresponds to expression() method in generated parser:
public final expression_return expression() throws RecognitionException {
  //initialization
  try {
    //parsing
  }
  catch (RecognitionException re) {
    reportError(re);
    recover(input,re);
    retval.tree = (Object) adaptor.errorNode(input, retval.start, input.LT(-1), re);
  } finally {
  }
  //return result;
}

If an error happens, parser will:
  • report error to the console,
  • recover from the error,
  • add an error node (instead of an ordinary node) to the abstract syntax tree.

Error reporting in parser is little bit more complicated than error reporting in lexer:
/** Report a recognition problem.
  *
  *  This method sets errorRecovery to indicate the parser is recovering
  *  not parsing.  Once in recovery mode, no errors are generated.
  *  To get out of recovery mode, the parser must successfully match
  *  a token (after a resync).  So it will go:
  *
  *   1. error occurs
  *   2. enter recovery mode, report error
  *   3. consume until token found in resynch set
  *   4. try to resume parsing
  *   5. next match() will reset errorRecovery mode
  *
  *  If you override, make sure to update syntaxErrors if you care about that.
  */
 public void reportError(RecognitionException e) {
  // if we've already reported an error and have not matched a token
  // yet successfully, don't report any errors.
  if ( state.errorRecovery ) {
   return;
  }
  state.syntaxErrors++; // don't count spurious
  state.errorRecovery = true;

  displayRecognitionError(this.getTokenNames(), e);
 }

This time we have two possible options:
  • replace catch clause in a parser rule method by own handling,
  • override parser methods.

Changing Catch in Parser
Antlr provides two ways how to change generated catch clause in the parser. We will create two new grammars, each demonstrates one way how to do it. In both cases, we will make parser exit upon first error.

First, we can add rulecatch to parser rule of new S002HelloWordWithErrorHandling grammar:
expression : SALUTATION ENDSYMBOL;
catch [RecognitionException e] {
  //Custom handling of an exception. Any java code is allowed.
  throw new S002HelloWordError(":(", e);
}

Of course, we had to add import of S002HelloWordError exception into headers block:
@parser::header {
  package org.meri.antlr_step_by_step.parsers;

  //add imports (see full line on Github)
  import ... .S002HelloWordWithErrorHandlingCompiler.S002HelloWordError;
}

The compiler class is almost the same as before. It declares new exception:
public class S002HelloWordWithErrorHandlingCompiler extends AbstractCompiler {

  public CommonTree compile(String expression) {
    // no change here
  }

  @SuppressWarnings("serial")
  public static class S002HelloWordError extends RuntimeException {
    public S002HelloWordError(String arg0, Throwable arg1) {
      super(arg0, arg1);
    }
  }
}

ANTLR will then replace default catch clause in expression rule method with our own handling:
public final expression_return expression() throws RecognitionException {
  //initialization
  try {
    //parsing
  }
  catch (RecognitionException re) {
    //Custom handling of an exception. Any java code is allowed.
    throw new S002HelloWordError(":(", e); 
  } finally {
  }
  //return result;
}

As usually, the grammar, the compiler class and the test class are available on Github.

Alternatively, we can put rulecatch rule in between the header block and first lexer rule. This method is demonstrated in S003HelloWordWithErrorHandling grammar:
//change error handling in all parser rules
@rulecatch {
  catch (RecognitionException e) {
    //Custom handling of an exception. Any java code is allowed.
    throw new S003HelloWordError(":(", e);
  }
}

We have to add import of S003HelloWordError exception into headers block:
@parser::header {
  package org.meri.antlr_step_by_step.parsers;

  //add imports (see full line on Github)
  import ... .S003HelloWordWithErrorHandlingCompiler.S003HelloWordError;
}

The compiler class is exactly the same as in previous case. ANTLR will replace default catch clause in all parser rules:
public final expression_return expression() throws RecognitionException {
  //initialization
  try {
    //parsing
  }
  catch (RecognitionException re) {
    //Custom handling of an exception. Any java code is allowed.
    throw new S003HelloWordError(":(", e); 
  } finally {
  }
  //return result;
}

Again, the grammar, the compiler class and the test class are available on Github.

Unfortunately, this method has two disadvantages. First, it does not work in lexer, only in parser. Second, default report and recovery functionality works in a reasonable way. It attempts to recover from errors. Once it starts recovering, it does not generate new errors. Error messages are generated only if the parser is not in error recovery mode.

We liked this functionality, so we decided to change only default implementation of error reporting.


Add Methods and Fields to Generated Classes
We will store all lexer/parser errors in private list. Moreover, we will add two methods into generated classes:
  • hasErrors - returns true if at least one error occurred,
  • getErrors - returns all generated errors.

New fields and methods are added inside @members block:
@lexer::members {
  //everything you need to add to the lexer
}

@parser::members {
  //everything you need to add to the parser
}

Members blocks must be placed between header block and first lexer rule. The example is in grammar named S004HelloWordWithErrorHandling:
//add new members to generated lexer
@lexer::members {
  //add new field
  private List<RecognitionException> errors = new ArrayList <RecognitionException> ();
  
  //add new method
  public List<RecognitionException> getAllErrors() {
    return new ArrayList<RecognitionException>(errors);
  }

  //add new method
  public boolean hasErrors() {
    return !errors.isEmpty();
  }
}

//add new members to generated parser
@parser::members {
  //add new field
  private List<RecognitionException> errors = new ArrayList <RecognitionException> ();
  
  //add new method
  public List<RecognitionException> getAllErrors() {
    return new ArrayList<RecognitionException>(errors);
  }

  //add new method
  public boolean hasErrors() {
    return !errors.isEmpty();
  }
}

Both generated lexer and generated parser contain all fields and methods written in members block.

Overriding Generated Methods
To override a generated method, do the same thing as if you want to add a new one, e.g. add it inside @members block:
//override generated method in lexer
@lexer::members {
  //override method
  public void reportError(RecognitionException e) {
    errors.add(e);
    displayRecognitionError(this.getTokenNames(), e);
  }
}

//override generated method in parser
@parser::members {
  //override method
  public void reportError(RecognitionException e) {
    errors.add(e);
    displayRecognitionError(this.getTokenNames(), e);
  }
}

The method reportError now overrides default behavior in both lexer and parser.

Collect Errors in Compiler
Finally, we have to change our compiler class. New version collects all errors after input parsing phase:
private List<RecognitionException> errors = new ArrayList<RecognitionException>();

public CommonTree compile(String expression) {
  try {

    ... init lexer ...
  
    ... init parser ...
    ret = parser.expression();

    //collect all errors
    if (lexer.hasErrors())
      errors.addAll(lexer.getAllErrors());
  
    if (parser.hasErrors())
      errors.addAll(parser.getAllErrors());
  
    //acquire parse result
    ... as usually ...
  } catch (RecognitionException e) {
    ...
  }
}
  
/**
* @return all errors found during last run
*/
public List<RecognitionException> getAllErrors() {
  return errors;
}

We must collect lexer errors after parser finished its work. The lexer is invoked from it and contain no errors before. As usually, we placed the grammar, the compiler class, and the test class on Github.

Download tag 003-S002-to-S004HelloWordWithErrorHandling of antlr-step-by-step project to find all three error handling methods in the same java project.

To Be Continued

We covered everything except the most important thing, lexer and grammar rules. Next post will only about them. We will create a compiler for boolean expression language and show how to influence generated abstract syntax tree structure.

128 comments:

selamet HARIADI said...

GREAT POST about ANTLR... how to make a simple grammar java to explain hello world or example If...Else ???

be Best Together!
_
@seHARIADI

Collins said...

Hiya! I simply wanted to tell that you sure succeeded in customizing a magnificent site. Also I would like to ask you one thing that I am curious of. Do you plan to write professionally or having a blog is basically just a hobby of yours?

selamet hariadi said...

This is part of my research to make Java Coding Game.

manao' said...

I want to build a tool which will accept word list of a language and rules, to convert to corresponding word of another language in IPA(International Phonetic Alphabet) symbol. Can I do that with ANTLR ? #computational Linguistics

Meri said...

@Manao: I'm not sure what exactly are you trying to do. ANTLR is designed for compiler programmers, not for human language translation. It is probably worth trying.

AS said...

If you are working with Maven, there are some useful plugins to work with ANTLR4 grammars - https://blog.sourceclear.com/useful-maven-plugins-for-working-with-ANTLR-4-grammars/

Heet Sheth said...

Thanks for the tutorial. But how can we generate two different files from the input by validating grammar? I'm able to parse valid language through the grammar, and able to print in the output file.But how to split the input according to the grammar? Like say if language satisfies the given grammar then it should be placed in one file, otherwise in the other file.

Anonymous said...

[Showcase list](http://www.antlr.org/showcase/list) is dead (404). I did not manage to get a good alternative in the current page. ANTLR3 still has it, however: [antlr3 showcase list](http://www.antlr3.org/showcase/list.html).

Anonymous said...

It seems my previous comment needs extension: all `antlr.org` links need to be replaced with `antlr3.org`.

Revathy said...

Good one you explain. all building and civil related work to must use for the pre engineering process is very well done to introduce. Majorly access material is boom lift rental for access and tools used for core work. Thanks for the opportunity. and Thanks for post and creadited to Sendhamarai Engineering.

Unknown said...

Thank you so much. Your works are fantastic and very useful for all of us. We are waiting for your next post. Thank you.
Seo Services In Delhi

Unknown said...

Thanks for providing good information,Thanks for your sharing python Online Training

SEO BACKLINKS said...

SEE MORE ARTICLE IN HERE. CLICK IN HERE

latesttechnologyblogs said...

I like your blog, I read this blog please update more content on python, further check it once at python online course

singa said...

best baby walker

Robbie Royce said...

Wow, Great information and this is very useful for us.

Aluminium scaffolding hire

luckys said...

123movies

whatsapp plus themes said...

entertainment whatsapp groups

Raj Maan said...

online earning whatsapp groups

RoyceRobbie said...

Good information and, keep sharing like this.

Crm Software Development Company in Chennai

Anonymous said...

Nice article
Thanks for sharing us
Please support us
MX player pro apk download

shanthumA said...

Nice post, you provided a valuable information, keep going.

Prestashop ecommerce development company chennai

Nandhakumar said...

Nice information keep sharing like this.

scaffolding dealers in chennai
Aluminium scaffolding dealers in chennai

Devender Gupta said...

https://gizmoxo.com/facebook-stylish-names-list/
https://gizmoxo.com/netflix-cookies/
https://gizmoxo.com/free-netflix-account/
https://gizmoxo.com/netflix-mod-apk-premium/
https://gizmoxo.com/download-kingoroot-apk/

Devender Gupta said...

https://dtcbus.online/
https://dtcbus.online/pass
https://dtcbus.online/route
https://dtcbus.online/download

Destiny Solutions LLP said...

Netsuite Quickbooks Integration

CentORG said...

IIT JEE Coaching in Patna | IIT JEE Institute in Patna | NEET Coaching in Patna | Medical Coaching in Patna | JEE Mains, JEE Advance Coaching in Patna | Europa Classes

JEE Mains, JEE Advance Coaching in Patna
Hot offers on Amazon]
Tips on technology

Anushka Sen

CentORG said...

ipsontechnology

learn every time new tips on technology

Hey my audience, in this website we’ll post about many tips on technology. many tips on hacking, education and many entertainment niche. i’ll post somethin Tips on technology
g special for you, Everyday
So check out it from here

CentORG said...

sale all product in hindi

Hindisales provide you most productive Offers notification for you. If you Want to buy any products for you. Just check offers on that products in hindisales and check it out from here
Hot offers on Amazon]

CentORG said...

IIT JEE Coaching in Patna | IIT JEE Institute in Patna | NEET Coaching in Patna | Medical Coaching in Patna | JEE Mains, JEE Advance Coaching in Patna | Europa Classes

JEE Mains, JEE Advance Coaching in Patna
Hot offers on Amazon]
Tips on technology

Anushka Sen

Abhishek Rajpoot said...

WhatsApp Status Video Download :WhatsApp introduced the status feature in 2015, in which we can share images, videos, and gifs as our story for 24 hours. Before this feature, WhatsApp had only text status option in which we can write our bio, but the new status feature is different. The story or status disappears after 24 hours and can’t be archived as still in WhatsApp.

Boy attitude status video download for whatsApp
Boy attitude status video download
Boy attitude status video download

Most romantic status video download for whatsApp
Sad video status download
Most Romantic status video download

video status download for whatsApp


we have latest & best collection of video status download for whatsapp

Sandhu said...

Filmyhit
teri meri jodi full movie download Filmyhit
section 375 full movie download Filmyhit
fauji di family full movie download
family 420 full movie download
Vipp2541
Filmyhit Download Hollywood Bollywood movies
Sanju Full Movie Download Filmyhit
Whatsapp Group Links
Whatsapp Group Links

Sandhu said...

Minecraft x-ray resource pack
Satta king 786
dhankesari
Filmyhit
Xray texture pack
xray ultimate texture packs
optifine hd mod
Naukar Vahuti Full movie download
Mission Mangal Full movie download

Devender Gupta said...

WhatsApp group links

MIUI theme

Devender Gupta said...

Dr Driving is one of the my favourite game ever and today I am going to share Dr Driving Mod Apk
https://www.drdrivingmodapk.xyz/

Devender Gupta said...

redmi note 8 pro gcam

https://www.google.com/amp/s/gizmoxo.com/install-google-camera-gcam-on-redmi-note-8-pro/%3famp

Gizdoc said...

Really great article, you guys are doing a great work, keep posting good stuff, If your audience is into Tech do share 30 MiUi 11 Tips and Tricks
Gizdoc Tech Paradise

pnjsharptech said...

PNJ Sharptech is a leading Social Media Optimization company in India, specializing in handling both organic and paid Social Media Marketing (SMM) campaigns successfully. We have many years of experiencing increasing online social presence on various social media platforms such as Facebook, Twitter, LinkedIn and Pinterest, and many others. Our SMO experts have a rich knowledge of increasing traffic and maintaining the online social reputation for a long period. How our SMO services make you different from others? Our low-cost social media marketing services are very helpful to build your online reputation and increase sales.

BB Arora said...

Guglu muglu with its Punjabi Song LYRICS by Jasmine Sandlas in songwriting of Ranbir Grewal is a latest track. Lavkesh Vishwakarma is director music Rosleen Sandlas shot the music video for it. Read Guglu muglu Song Full Song Lyrics and also watch the official music video.GUGLU MUGLU Song LYRICS – Jasmine Sandlas

BB Arora said...

40 Lakh mp3 song download pagalworld, tik tok viral song ,Mr jatt. GetSongName.com – Presenting the audio song ” 40 Lakh ” this song by Jerry Burj Ft. Ellde Fazilka , song is been written Ellde Fazilka40 Lakh mp3 song download pagalworld

BB Arora said...

The punjabi song based on friendship mere yaar modh do is sung and lyrics penned by Guru Randhawa & Millind Gaba while music composed by Millind Gaba.

Admin said...

Super Dj Remix Song New Latest Song Available On This Website,

Good Job Sir

Latest Official Song Download Now Click Here

Download Now Click Here

Digital Paal said...

Thanks for sharing the important and awesome information, Thank you. SMM Services Delhi, SMO Services Delhi

Zero Stock Brokerage said...

Thanks for sharing the important and awesome information, Thank you. Open demat account online

Anonymous said...

Nice Blog
Thanks for sharing this information
Get details of the blog performance
android apps apkzm
android apps apkzm
android apps apkzm

Anonymous said...

Excellent Blog! I would like to thank for the efforts you have made in writing this post. I am hoping the same best work from you in the future as well.
bestindia
click here
best-india

Anonymous said...

androidapps
android apps apkzm
android
aapps apkzm
apps apkzm

Anonymous said...

Thanks for sharing valuable information.It will help everyone.keep Post.
appsapkzm
android apps apkzm
android apps
go her
clickapkzm

HaryaliOrganics said...

It's really nice and meaningful. it's really cool blog, Thank you.Buy Organic fruits online in Delhi

Unknown said...

It's really nice and meaningful. it's really cool blog, Thank you. Acupressure Foot Mat - Magnetotherapy pyramid - Powermat 2000

Unknown said...

Great Article Cloud Computing Projects

Networking Projects

Final Year Projects for CSE

JavaScript Training in Chennai

JavaScript Training in Chennai

The Angular Training covers a wide range of topics including Components, Angular Directives, Angular Services, Pipes, security fundamentals, Routing, and Angular programmability. The new Angular TRaining will lay the foundation you need to specialise in Single Page Application developer. Angular Training

Mike said...


Download the latest USB Drivers for windowas 10

Bed Regular said...

The information which you have provided is very good. It is very useful who is looking for
food and nutrition course
Best Distance Education College

Aditi Gupta said...

Pretty article! I found some useful information in your blog, it was awesome to read, thanks for sharing this great content to my vision, keep sharing. Golden Triangle Tour Package India

Rohit Kumar said...

Hii, thankyou so much sir for in this problem solution. it is valueable post.
Also Check:

Short Instagram Captions For Guys
Two Word Captions For Instagram
3 Word Captions For Instagram
Hot Captions For Instagram
Classy Captions For Instagram

Rohit Kumar said...

hey gus, here some amazing surprize so click and go there....
check this:
Funny Jokes
Funny Jokes
Funny Jokes
Funny Jokes
Funny Jokes
Funny Jokes
Funny Jokes
Funny Jokes
Funny Jokes
Funny Jokes
Funny Jokes
Funny Jokes
Funny Jokes
Funny Jokes
Funny Jokes
Funny Jokes
Funny Jokes
Funny Jokes
Funny Jokes
Funny Jokes

Unknown said...

We tell you about Income Tax Return.

This tax in India since 1961 through the multiple Amendment of the Constitution of India.

This article is really helpful to you, Every business and offices required Income Tax Return in Delhi and Income Tax Return in Faridabad. We also provide professional service for tax return, tax guidanace in Income Tax Return in Karnataka as well as we provide Income Tax Return in Ahmedabad and Income Tax Return in Kerala.

Get complete detail about income tax, tax refund status, income tax filing procedure, pan number, tax guide. Tax experts in India provided by TaxWala will assist you through the entire process. Online Income Tax Return File your return application & get your acknowledgement Online. Agents and consultanst at TaxWala help you to file income tax return done online in 3 hours without any problem.

Our Tax Consultants also available for Income Tax Return in Gujarat, Income Tax Return in Haryana, Income Tax Return in Rajasthan and Income Tax Return in Punjab.

We are best in taxation services, itr filing, income tax return in india etc.

For SEO, SEM - Top 10 Digital Marketing Company In India

Keerthi55 said...

python online training
python training

Cracker said...

Excellent post. Acronis True Image 2022 Crack
Windows Movie Maker 2022 Crack
Microsoft Office 2022 Crack
Adobe Photoshop 2022 Crack

Awais Chughtai said...

what a informative and knowlegeable websites.Hotstar Apk Crack

Unknown said...

hi sir, Wow really interesting article, may later be able to share other helpful information are more interesting. Thank you!Icecream PDF Split Merge Pro Crack

sherazhaider said...

This impressed me so much amazing. Keep working and providing information
patch

Crackcon said...

FonePaw Data Recovery Crack is capable of transferring data from digital cameras, SD cards, and external hard drives that are connected to your computer.
windowsloader.org


crackerr said...

hi sir, Wow really interesting article, may later be able to share other helpful information are more interesting. Thank you
Directory Lister Pro with Serial Delivers

Malik said...

Your post is based on the informative things. Your writing skills is really good. Keep on hardworking if you want to progress in the future. Also give us some more informative post. Thanks again for the great post. Cheers!
Updated Version

Anonymous said...

I am very happy to read the posts on this site which contain a lot of useful information, thank you for providing this kind of information. Keep it up man and also give us some more informative posts. Cheers!
PhpStorm

serial said...

Please keep us informed like this
Click Here

findcrack said...

Leawo Prof. Media is an amazing Post with good content.FIND CRACK is the best crack software site for all Mac and Windows users all over the world.

crackerr said...

hi sir, Wow really interesting article, may later be able to share other helpful information are more interesting. Thank you
click this link

sherazhaider said...


My mind was blown by this.Keep up the great work!
forensic cracks

Anonymous said...

Thanks for providing this resource for free. It is a great resource. It's great to see websites that offer free resources that are of high quality. It's the same thing that happens every time. Let's see some more informative posts as well. Salutations!
TunesKit M4V Converter

serial said...

It’s great and fantastic piece. Keep it up as I look forward to read more from this website.
YouTube to Mp3 Converter Crack Download

sherazhaider said...

What an incredible piece of work! Keep up the great work!
tracer license key

crackerr said...

Hello sir, really great article, maybe later I can share other more interesting useful information. Thanks avast cleanup premium

Salman said...

I love your writing style really enjoying this web site.
thanks for Share with us this great and informative post post.
Easyserialkeys

crack said...

hi Dear, Thank you for sharing your details and experience. I think it very good for me. Keep it up! Also May you like Advanced Driver updater crack

hotpcsoft said...

Hi, I have to say I am impressed. I rarely come across such an informative and interesting blog,
and let me tell you that you nailed it.
Musify Crack license key

crackerr said...

It’s great and fantastic piece. Keep it up as I look forward to read more from this website. Windows 11 Activation txt

Khan Honey said...

hi sir, Wow really interesting article, may later be able to share other helpful information are more interesting. Thank you microsoft office

vinoth said...

nice blog
Internship providing companies in chennai | Where to do internship | internship opportunities in Chennai | internship offer letter | What internship should i do | How internship works | how many internships should i do | internship and inplant training difference | internship guidelines for students | why internship is necessary

Unknown said...

nice post..
net coure
net training

DriverPack Solution Offline said...

K-Lite Codec Pack Full Crack is one of the most comprehensive codecs and related tool packs available. It is the most basic version, and it includes everything you need to play common video file types like MKV, AVI, MP4, and FLV. It performs admirably even on low-end PCs and comes with no frills.

Oliver said...

Check the latest Uavs Stocktwits price, statistics, financial data and chart of Uavs Stocktwits from different exchanges. Also includes historical data which can be used for technical analysis, comparison and investment decision. The interactive stock chart will display detailed technical markers at major prices, you can drag it to a different time period to plot and highlight the technical pattern.

Oliver said...

The Vo Colorstreet Com Login Prepaid Online Login Page! Here You Will Be Able To Manage Your Vo Colorstreet Com Login Prepaid Account From Your Device Or Computer Browser.

Sue Hillium said...

Great Post man!
https://windowsactivators.org/ms-office-365-product-key-2019/

DC said...

This is an excellent article. Especially the closing section, this information is quite useful. Such information is very important to me. I'd been looking for this particular piece of information for a long time. Thank you for your time and consideration, and best wishes.
immitation jewelry wholesale in india

crackspro said...

Thanks for Sharing such an amazing article. Keep working... Your Site is very nice, and it's very helping us.. this post is unique and interesting, thank you for sharing this awesome information Adobe Character Animator Crack/

Proversion said...

I really like your work it was amazing and very helpful.... https://www.flickr.com/people/194912962@N04/

Top Cracking said...

https://lexsrv3.nlm.nih.gov/fdse/search/search.pl?match=0&realm=all&terms=https://crackitems.com/

Top Cracking said...

https://community.windy.com/user/brockskaaning8

My Fantasy Ideas said...

My Friend suggest me your website and its worth to read your articles My Fantasy Ideas - Jokes | Shayari | Quotes | Status | Names Ideas

Jehra anjum said...

Nice post thanks for share Free Games

Unknown said...

To know about automated help desk and service desk with rezolve.ai, visit the link with the link here: https://www.rezolve.ai/home

Unknown said...

Universal Keygen Generator  Latest Version Download The disposable news is that you simply can now activate any serial key with the Universal Keygen Generator. Many of those demands are too expensive. To counter this, the developers develop Universal Keygen Generator 2021 Crack, which is particularly helpful for business people and students in using many of those applications. Still, they limit only […]

oliver said...

There is no limit to how much one can share information, so keep up the good work. Keep up the good work!https://crackdue.com/minitab-18-crafree-download/

Unknown said...

This Is Stuff: Antlr Tutorial - Hello Word >>>>> Download Now

>>>>> Download Full

This Is Stuff: Antlr Tutorial - Hello Word >>>>> Download LINK

>>>>> Download Now

This Is Stuff: Antlr Tutorial - Hello Word >>>>> Download Full

>>>>> Download LINK jx

crackerr said...

Thanks Admin For Sharing Your Great Ides. If you want to Download the Official Crack Then Click Here
UltraCopier Ultimate Crack

AFM Logistics said...

AFM Logistics Pvt Ltd is an international freight forwarding and customs clearing company established in Delhi. The company was constituted in 2012 and is indulged in providing complete logistics solution. The company has its own setup and wide network of agents throughout the world. Best Custom Clearing Company in Delhi . They are the best air cargo and ocean freight forwarding company in Delhi, India. AFM Logistics Pvt Ltd has been working as Import and Export Agent in India since 2012. They have been providing personal baggage shipping services in India for a very long time.

Mari said...

I value the information you provide. Your website's overall appearance, let alone what it accomplishes, is truly remarkable.
Download Here

priya said...

Nice Post Your content is very inspiring and appriciating I really like it please visit my site for
gali satta
satta result
satta king
Satta Bajar
सट्टा किंग
delhi satta king
Disawar satta king
Satta King 786

E Learning Services said...

The curriculum is a vital part of both online and offline teaching. A comprehensive curriculum means that half of the task of a good teaching pedagogy has been fulfilled. If you are in search of a good curriculum development service provider curriculum development service provider then Acadecraft is sure to be your first choice. We provide premium curriculum services at affordable prices.

Dr. Namita Nadar said...

if anyone wants to leads a healthy lifestyle, he or she can do so by following a weight loss tips, or by following a healthy lifestyle laid down by the nutritionist. Here comes one clinic which can make you fit and healthy by making you follow their diet plans and certain remedies laid down by her . Dr. Namita Nadar is the Best Dietitian and Nutritionist in Noida and Delhi NCR. The clients are very happy with her as she has improved their quality of living with her good diet plans according to the customers requirements. She is the Best Dietitian and nutritionist in Noida NCRif anyone wants to avail her services, one can call on their number or contact through their website or mail on their gmail id https://namitadietclinicnoida.com

drnamitanadardietclinic@gmail.com
+919540364364

Safaiwale said...

Pest Control Services in Delhi NCR, Pest Control Services in Gurgaon, Pest Control Services in Noida, Pest Control Services in Ghaziabad, Pest Control Services in Vaishali, Pest Control Services in Thane, Pest Control Services in Surat

bk industries said...

Operating from New Delhi, Delhi, India, BK IDNSUTRIES came into existence in the year 1963. We are known in the national and international market as a trustworthy manufacturer and we deal in all type of single & double facers corrugated rollers and industrial gears. Our speciality is Best UV Shaped Corrugating Rolls. Our products can meet the demand of different clients with a large quantity of models and complete specifications.

cleanservice24x7 said...

cleanservice24x7 is one of the best home cleaning service in chandigarh.Customer comfort and customer preference are our first priorities. We provide best cleaning service at a completely low rate with zero connectivity at your doorstep.we also provide car dry cleaning service in chandigarh.

developn design said...

Developn designs is best basic computer training provider in Chandigarh.
basic computer training in chandigarh
6week industrial training in Chandigarh

Media Foster said...


Media Foster always charges reasonable giving clients access to every detail about their work. We assure you of better traffic than your competitors.
digital marketing company in Mohali
best industry training Company in Mohali

veerediwedding said...

We have give best luxury car rental Services since long periods of experience in offering top luxury cars with top class chauffeur.if you need more information visit our website.
luxury car rental in Amritsar
luxury wedding cars in Chandigarh

Safaiwale said...

Thank for sharing Great Information. best pest control services provider, provide you 100% quality, effective, and trustworthy services at affordable prices.

Aashish said...

Guppy Gold Logistics

info@guppygold.com
+91 859-585-1414

https://www.guppygold.com/

Guppy Gold offers a number of air freight services with day-specific or day-definite scheduling, door-to-door service. We have a wide variety of air freight services such as express, on-board courier, daily flights and consolidated services.

Low Cost Air Freight Forwarding Services | Best USA to India Air Freight Company

Safaiwale said...

Thanks for sharing Wonderful blog. it is great information is this blog. House Cleaning Services, Office Cleaning Services

Jehra anjum said...

Nice post thanks for share This valuble knowledge

jackowen said...

Our Assignment Help service increase the chances of getting the higher grades to 100% for the students who take our help. We have a good record of delivering the high quality paper content with the best paper solutions.

Future Fit Wellness said...

The Naabhi Chakra tablet absorbs the body far deeper and more quickly, boosting immunity. By carefully testing the addition of various substances, our workers created these tablets that improve immunity. So, if you're interested in purchasing this Naabhi Chakra Tablet, please visit our website.

assignment help said...

Make a strong link between your personal goals and the hours you invest in taking virtual classrooms to secure your career. There is plethora of online service that provides wonderful assistance but one of them is “take my online class for me” tool that are a high-quality service operator and outperform all of their rivals in this sector when it comes to offering knowledgeable solutions.

Anonymous said...

A Hyderabad-based developer will have many years of experience in ecommerce development. These experts are skilled in customer service and customer satisfaction. They can help you get your website up-and-running as quickly as possible. You can also choose a developer company based on their experience and price. There are many options available to you. A good development company will make the entire process easy.
https://vstechnosolutions.com/

Anonymous said...

If you are looking for efficient and reliable service for your Sony electronics products, then you have come to the right place. Sony Hyderabad offers a wide range of services for all Sony products. The company provides a variety of services including accessories, mobile phones, as well as air conditioners or LED televisions. If your product has been damaged, you can contact the center via email or by calling a toll-free number.
https://www.sonytvservicing.in/

Stella Kelson said...
This comment has been removed by the author.
Aly James Lab VSDS-X 2.0.2 Crack said...


I am very happy to read this article. Thanks for giving us Amazing info. Fantastic post.
Thanks For Sharing such an informative article, Im taking your feed also, Thanks.fonedog-toolkit-for-ios-crack/

Anonymous said...

If you are facing a problem with your TV, the best option is to go to a Sony TV service center in Secunderabad. Sony products are generally covered by a one-year limited warranty and are repaired for free.
https://www.sonytvservicing.in/

Anonymous said...

If you are looking for Kota stone polishing services in Hyderabad, you have come to the right place. SDL Marble Polishing offers a variety of services and is equipped with advanced technology to bring the best results to your floors.
https://sdlmarblepolishing.com/best-marble-polishing-in-hyderabad.php

Aly James Lab VSDS-X 2.0.2 Crack said...


I am very happy to read this article. Thanks for giving us Amazing info. Fantastic post.
Thanks For Sharing such an informative article, Im taking your feed also, Thanks.ratiborus-kms-tools-portable-crack/

Softwears said...

I guess I am the only one who came here to share my very own experience. Guess what!? I am using my laptop for almost the past 2 years, but I had no idea of solving some basic issues. I do not know how to Crack Softwares Free Download But thankfully, I recently visited a website named xxlcrack.net/
Process Lasso Pro Crack
Adobe Character Animator CC Crack

Dlf heights said...

apartments in gurgaon
ready to move apartments in gurgaon
We at DLF flats, very well understand your feelings and emotions behind buying your own space in this era. We provide you fully furnished DLF flats in Delhi & Gurugram.

intellimindz said...

TestComplete Training in Chennai
Catia Training in Chennai
SolidWorks Training in Chennai|

navin said...

Nice post,
If you are looking for the best commercial cleaning service in Mumbai then SD Hospitality provides the best service for the last 10 years.

www.sdhospitality.in

crack-win said...

Your Work is So Great....https://crack-win.com/

Anonymous said...

How to Start a Medical Store? Generic Aadhaar
The pharmaceutical industry in India is growing at a very fast pace since last decade. Due to cost efficiency, increased availability and high demand, Indian medicines are rapidly spreading widely all over the world. This area is a major area of ​​focus. Starting your own medical store is a good business option as its business profit margin is quite high in India. Another positive thing about the medical profession is that it is not easily affected by the economic crisis. A recent example is a covid pandemic when many people were losing jobs and offices were closed. The medical store was not closed but they were in great need.

Post a Comment